diff --git a/.travis.yml b/.travis.yml index fb3d2ef6784e..9c1d004d6943 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,8 +56,8 @@ matrix: if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try) - env: INTEGRATION=rust-lang-nursery/chalk if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try) - - env: INTEGRATION=rust-lang/rls - if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try) + # - env: INTEGRATION=rust-lang/rls + # if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try) - env: INTEGRATION=Geal/nom if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try) - env: INTEGRATION=rust-lang/rustfmt diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e9013985eaf..46c2be3010de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log All notable changes to this project will be documented in this file. +See [Changelog Update](doc/changelog_update.md) if you want to update this +document. ## Unreleased / In Rust Beta or Nightly @@ -1088,6 +1090,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 @@ -1152,6 +1155,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/CONTRIBUTING.md b/CONTRIBUTING.md index 3eff20cead74..2a85197068f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Hello fellow Rustacean! Great to see your interest in compiler internals and lin Clippy welcomes contributions from everyone. There are many ways to contribute to Clippy and the following document explains how you can contribute and how to get started. If you have any questions about contributing or need help with anything, feel free to ask questions on issues or -visit the `#clippy` IRC channel on `irc.mozilla.org` or meet us in `#wg-clippy` on [Discord](https://discord.gg/rust-lang). +visit the `#clippy` IRC channel on `irc.mozilla.org` or meet us in `#clippy` on [Discord](https://discord.gg/rust-lang). All contributors are expected to follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html). @@ -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/README.md b/README.md index 8bcfd8a8430c..e5da763607bd 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 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 db407565b19b..b53a55799713 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -123,13 +123,13 @@ pub fn gen_deprecated(lints: &[Lint]) -> Vec { 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/Cargo.toml b/clippy_lints/Cargo.toml index 956bc858a179..48133cc5b02b 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,7 +28,8 @@ serde = { version = "1.0", features = ["derive"] } toml = "0.5.3" unicode-normalization = "0.1" pulldown-cmark = "0.5.3" -url = "2.1.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" smallvec = { version = "0.6.5", features = ["union"] } diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 32ca1cc1bb99..347c6478b47c 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -3,7 +3,7 @@ use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; use crate::consts::{constant, Constant}; -use crate::utils::{in_macro_or_desugar, is_direct_expn_of, is_expn_of, span_help_and_lint}; +use crate::utils::{is_direct_expn_of, is_expn_of, span_help_and_lint}; declare_clippy_lint! { /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls. @@ -55,12 +55,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants { } }; if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") { - if in_macro_or_desugar(debug_assert_span) { + if debug_assert_span.from_expansion() { return; } lint_assert_cb(true); } else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") { - if in_macro_or_desugar(assert_span) { + if assert_span.from_expansion() { return; } lint_assert_cb(false); diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 64c8a715d5ef..1159df5475ac 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -2,8 +2,8 @@ use crate::reexport::*; use crate::utils::{ - in_macro_or_desugar, is_present_in_source, last_line_of_span, match_def_path, paths, snippet_opt, span_lint, - span_lint_and_sugg, span_lint_and_then, without_block_comments, + is_present_in_source, last_line_of_span, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg, + span_lint_and_then, without_block_comments, }; use if_chain::if_chain; use rustc::hir::*; @@ -412,7 +412,7 @@ fn is_relevant_expr(cx: &LateContext<'_, '_>, tables: &ty::TypeckTables<'_>, exp } fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attribute]) { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } diff --git a/clippy_lints/src/block_in_if_condition.rs b/clippy_lints/src/block_in_if_condition.rs index 4fd9e271af08..c2ff8c83373b 100644 --- a/clippy_lints/src/block_in_if_condition.rs +++ b/clippy_lints/src/block_in_if_condition.rs @@ -54,7 +54,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { if let ExprKind::Closure(_, _, eid, _, _) = expr.node { let body = self.cx.tcx.hir().body(eid); let ex = &body.value; - if matches!(ex.node, ExprKind::Block(_, _)) && !in_macro_or_desugar(body.value.span) { + if matches!(ex.node, ExprKind::Block(_, _)) && !body.value.span.from_expansion() { self.found_block = Some(ex); return; } @@ -79,7 +79,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { if let Some(ex) = &block.expr { // don't dig into the expression here, just suggest that they remove // the block - if in_macro_or_desugar(expr.span) || differing_macro_contexts(expr.span, ex.span) { + if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) { return; } span_help_and_lint( @@ -96,7 +96,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition { } } else { let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); - if in_macro_or_desugar(span) || differing_macro_contexts(expr.span, span) { + if span.from_expansion() || differing_macro_contexts(expr.span, span) { return; } // move block higher diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index caf418c9b5b4..b520a3e25769 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -1,6 +1,5 @@ use crate::utils::{ - get_trait_def_id, implements_trait, in_macro, in_macro_or_desugar, match_type, paths, snippet_opt, - span_lint_and_then, SpanlessEq, + get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_then, SpanlessEq, }; use if_chain::if_chain; use rustc::hir::intravisit::*; @@ -106,7 +105,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> { } // prevent folding of `cfg!` macros and the like - if !in_macro_or_desugar(e.span) { + if !e.span.from_expansion() { match &e.node { ExprKind::Unary(UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)), ExprKind::Binary(binop, lhs, rhs) => match &binop.node { diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 54947a6a6713..88b8d8688b66 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -9,7 +9,7 @@ use rustc::{declare_tool_lint, impl_lint_pass}; use syntax::ast::Attribute; use syntax::source_map::Span; -use crate::utils::{in_macro_or_desugar, is_allowed, match_type, paths, span_help_and_lint, LimitStack}; +use crate::utils::{is_allowed, match_type, paths, span_help_and_lint, LimitStack}; declare_clippy_lint! { /// **What it does:** Checks for methods with high cognitive complexity. @@ -42,7 +42,7 @@ impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl CognitiveComplexity { fn check<'a, 'tcx>(&mut self, cx: &'a LateContext<'a, 'tcx>, body: &'tcx Body, span: Span) { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 12c83873641c..6c33f362633c 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -18,9 +18,7 @@ use rustc::{declare_lint_pass, declare_tool_lint}; use syntax::ast; use crate::utils::sugg::Sugg; -use crate::utils::{ - in_macro_or_desugar, snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then, -}; +use crate::utils::{snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then}; use rustc_errors::Applicability; declare_clippy_lint! { @@ -77,7 +75,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if !in_macro_or_desugar(expr.span) { + if !expr.span.from_expansion() { check_if(cx, expr) } } @@ -108,7 +106,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) { if let ast::ExprKind::Block(ref block, _) = else_.node; if !block_starts_with_comment(cx, block); if let Some(else_) = expr_block(block); - if !in_macro_or_desugar(else_.span); + if !else_.span.from_expansion(); if let ast::ExprKind::If(..) = else_.node; then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 01989625b45a..df354073df80 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,6 +1,4 @@ -use crate::utils::{ - get_parent_expr, higher, in_macro_or_desugar, same_tys, snippet, span_lint_and_then, span_note_and_lint, -}; +use crate::utils::{get_parent_expr, higher, 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}; @@ -109,7 +107,7 @@ declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - if !in_macro_or_desugar(expr.span) { + if !expr.span.from_expansion() { // skip ifs directly in else, it will be checked in the parent if if let Some(expr) = get_parent_expr(cx, expr) { if let Some((_, _, Some(ref else_expr))) = higher::if_block(&expr) { diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index e55490325eca..5e1a860ae80f 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,4 +1,4 @@ -use crate::utils::{in_macro_or_desugar, span_lint}; +use crate::utils::span_lint; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; use syntax::ast::*; @@ -27,7 +27,7 @@ declare_lint_pass!(DoubleParens => [DOUBLE_PARENS]); impl EarlyLintPass for DoubleParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index cf61683cb719..277844983658 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -1,6 +1,6 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use crate::utils::{camel_case, in_macro_or_desugar, is_present_in_source}; +use crate::utils::{camel_case, is_present_in_source}; use crate::utils::{span_help_and_lint, span_lint}; use rustc::lint::{EarlyContext, EarlyLintPass, Lint, LintArray, LintPass}; use rustc::{declare_tool_lint, impl_lint_pass}; @@ -248,7 +248,7 @@ impl EarlyLintPass for EnumVariantNames { let item_name = item.ident.as_str(); let item_name_chars = item_name.chars().count(); let item_camel = to_camel_case(&item_name); - if !in_macro_or_desugar(item.span) && is_present_in_source(cx, item.span) { + if !item.span.from_expansion() && is_present_in_source(cx, item.span) { if let Some(&(ref mod_name, ref mod_camel)) = self.modules.last() { // constants don't have surrounding modules if !mod_camel.is_empty() { diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs index 08c0b36855e2..9c8380ab7de7 100644 --- a/clippy_lints/src/eq_op.rs +++ b/clippy_lints/src/eq_op.rs @@ -1,6 +1,4 @@ -use crate::utils::{ - implements_trait, in_macro_or_desugar, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq, -}; +use crate::utils::{implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; @@ -52,7 +50,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp { #[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_or_desugar(e.span) { + if e.span.from_expansion() { return; } if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) { diff --git a/clippy_lints/src/erasing_op.rs b/clippy_lints/src/erasing_op.rs index 3ac2f90ce01b..190f4e7b56e8 100644 --- a/clippy_lints/src/erasing_op.rs +++ b/clippy_lints/src/erasing_op.rs @@ -4,7 +4,7 @@ use rustc::{declare_lint_pass, declare_tool_lint}; use syntax::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::{in_macro_or_desugar, span_lint}; +use crate::utils::span_lint; declare_clippy_lint! { /// **What it does:** Checks for erasing operations, e.g., `x * 0`. @@ -31,7 +31,7 @@ declare_lint_pass!(ErasingOp => [ERASING_OP]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ErasingOp { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if in_macro_or_desugar(e.span) { + if e.span.from_expansion() { return; } if let ExprKind::Binary(ref cmp, ref left, ref right) = e.node { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 751d8fd00830..6e8d4585161e 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,7 +1,6 @@ use crate::utils::paths; use crate::utils::{ - in_macro_or_desugar, is_expn_of, last_path_segment, match_def_path, match_type, resolve_node, snippet, - span_lint_and_then, walk_ptrs_ty, + is_expn_of, last_path_segment, match_def_path, match_type, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty, }; use if_chain::if_chain; use rustc::hir::*; @@ -40,7 +39,7 @@ declare_lint_pass!(UselessFormat => [USELESS_FORMAT]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessFormat { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if let Some(span) = is_expn_of(expr.span, "format") { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } match expr.node { diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index f20c95d7684c..463530211157 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,4 +1,4 @@ -use crate::utils::{differing_macro_contexts, in_macro_or_desugar, snippet_opt, span_note_and_lint}; +use crate::utils::{differing_macro_contexts, snippet_opt, 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}; @@ -107,7 +107,7 @@ impl EarlyLintPass for Formatting { /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Assign(ref lhs, ref rhs) = expr.node { - if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro_or_desugar(lhs.span) { + if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion() { let eq_span = lhs.span.between(rhs.span); if let ExprKind::Unary(op, ref sub_rhs) = rhs.node { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { @@ -139,7 +139,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::If(_, then, Some(else_)) = &expr.node; if is_block(else_) || is_if(else_); if !differing_macro_contexts(then.span, else_.span); - if !in_macro_or_desugar(then.span) && !in_external_macro(cx.sess, expr.span); + if !then.span.from_expansion() && !in_external_macro(cx.sess, expr.span); // workaround for rust-lang/rust#43081 if expr.span.lo().0 != 0 && expr.span.hi().0 != 0; @@ -205,7 +205,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { if !differing_macro_contexts(first.span, second.span) - && !in_macro_or_desugar(first.span) + && !first.span.from_expansion() && is_if(first) && (is_block(second) || is_if(second)) { diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs index baf7791b7921..2441dd914aff 100644 --- a/clippy_lints/src/identity_conversion.rs +++ b/clippy_lints/src/identity_conversion.rs @@ -1,6 +1,5 @@ use crate::utils::{ - in_macro_or_desugar, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, - span_lint_and_then, + match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then, }; use crate::utils::{paths, resolve_node}; use rustc::hir::*; @@ -34,7 +33,7 @@ impl_lint_pass!(IdentityConversion => [IDENTITY_CONVERSION]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if in_macro_or_desugar(e.span) { + if e.span.from_expansion() { return; } diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs index 1cd58a370945..55f8701ab18b 100644 --- a/clippy_lints/src/identity_op.rs +++ b/clippy_lints/src/identity_op.rs @@ -5,7 +5,7 @@ use rustc::{declare_lint_pass, declare_tool_lint}; use syntax::source_map::Span; use crate::consts::{constant_simple, Constant}; -use crate::utils::{clip, in_macro_or_desugar, snippet, span_lint, unsext}; +use crate::utils::{clip, snippet, span_lint, unsext}; declare_clippy_lint! { /// **What it does:** Checks for identity operations, e.g., `x + 0`. @@ -29,7 +29,7 @@ declare_lint_pass!(IdentityOp => [IDENTITY_OP]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if in_macro_or_desugar(e.span) { + if e.span.from_expansion() { return; } if let ExprKind::Binary(ref cmp, ref left, ref right) = e.node { diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index ceda6578182f..b1b05bdc17fd 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,5 +1,5 @@ use crate::utils::{ - in_macro_or_desugar, match_def_path, + match_def_path, paths::{BEGIN_PANIC, BEGIN_PANIC_FMT}, resolve_node, snippet_opt, span_lint_and_then, }; @@ -138,7 +138,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn { // checking return type through MIR, HIR is not able to determine inferred closure return types // make sure it's not a macro - if !mir.return_ty().is_unit() && !in_macro_or_desugar(span) { + if !mir.return_ty().is_unit() && !span.from_expansion() { expr_match(cx, &body.value); } } diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index ef0a75438379..eb29a6d436ab 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -4,8 +4,8 @@ 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, + get_trait_def_id, implements_trait, match_type, paths, return_ty, span_help_and_lint, trait_ref_of_method, + walk_ptrs_ty, }; declare_clippy_lint! { @@ -94,7 +94,7 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S 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) { + if impl_item.span.from_expansion() { return; } diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index 226809a2e28b..5a1713467601 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -1,6 +1,6 @@ //! lint when items are used after statements -use crate::utils::{in_macro_or_desugar, span_lint}; +use crate::utils::span_lint; use matches::matches; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; @@ -38,7 +38,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); impl EarlyLintPass for ItemsAfterStatements { fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { - if in_macro_or_desugar(item.span) { + if item.span.from_expansion() { return; } @@ -52,7 +52,7 @@ impl EarlyLintPass for ItemsAfterStatements { // lint on all further items for stmt in stmts { if let StmtKind::Item(ref it) = *stmt { - if in_macro_or_desugar(it.span) { + if it.span.from_expansion() { return; } if let ItemKind::MacroDef(..) = it.node { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index ea302ed9fc9a..a1c61edbba58 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,6 +1,4 @@ -use crate::utils::{ - get_item_name, in_macro_or_desugar, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty, -}; +use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; use rustc::hir::def_id::DefId; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -75,7 +73,7 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) { - if in_macro_or_desugar(item.span) { + if item.span.from_expansion() { return; } @@ -87,7 +85,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero { } fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3054f11c1769..0ae93c6147ab 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); @@ -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, @@ -794,12 +795,14 @@ 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, 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, @@ -870,7 +873,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, @@ -1032,7 +1034,9 @@ 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, methods::USELESS_ASREF, misc::SHORT_CIRCUIT_STATEMENT, @@ -1056,7 +1060,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/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 7b36fa7e284b..b1da7483a600 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -11,7 +11,7 @@ use rustc::{declare_lint_pass, declare_tool_lint}; // use rustc::middle::region::CodeExtent; use crate::consts::{constant, Constant}; use crate::utils::usage::mutated_variables; -use crate::utils::{in_macro_or_desugar, sext, sugg}; +use crate::utils::{sext, sugg}; use rustc::middle::expr_use_visitor::*; use rustc::middle::mem_categorization::cmt_; use rustc::middle::mem_categorization::Categorization; @@ -48,6 +48,12 @@ declare_clippy_lint! { /// dst[i + 64] = src[i]; /// } /// ``` + /// Could be written as: + /// ```rust + /// # let src = vec![1]; + /// # let mut dst = vec![0; 65]; + /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]); + /// ``` pub MANUAL_MEMCPY, perf, "manually copying items between slices" @@ -464,7 +470,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Loops { #[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_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } @@ -1028,7 +1034,7 @@ fn check_for_loop_range<'a, 'tcx>( body: &'tcx Expr, expr: &'tcx Expr, ) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index df10336d6d97..09c1f4b3c979 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -1,7 +1,6 @@ use crate::utils::paths; use crate::utils::{ - in_macro_or_desugar, is_copy, match_trait_method, match_type, remove_blocks, snippet_with_applicability, - span_lint_and_sugg, + is_copy, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg, }; use if_chain::if_chain; use rustc::hir; @@ -44,7 +43,7 @@ declare_lint_pass!(MapClone => [MAP_CLONE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapClone { fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) { - if in_macro_or_desugar(e.span) { + if e.span.from_expansion() { return; } diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 22093bfbee84..7d46478a6fd3 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -1,5 +1,5 @@ use crate::utils::paths; -use crate::utils::{in_macro_or_desugar, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then}; +use crate::utils::{iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc::hir; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -257,7 +257,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapUnit { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt) { - if in_macro_or_desugar(stmt.span) { + if stmt.span.from_expansion() { return; } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 52265ae55bf1..6b6fd2bb2087 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -2,8 +2,8 @@ use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::sugg::Sugg; use crate::utils::{ - expr_block, in_macro_or_desugar, 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, + 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, }; use if_chain::if_chain; use rustc::hir::def::CtorKind; @@ -597,7 +597,7 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: })); span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |db| { - if !in_macro_or_desugar(expr.span) { + if !expr.span.from_expansion() { multispan_sugg(db, msg.to_owned(), suggs); } }); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 21f9beeae037..271d9c672e80 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -8,7 +8,6 @@ use std::iter; use if_chain::if_chain; use matches::matches; use rustc::hir; -use rustc::hir::def::{DefKind, Res}; use rustc::hir::intravisit::{self, Visitor}; use rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass}; use rustc::ty::{self, Predicate, Ty}; @@ -18,7 +17,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 +26,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. @@ -264,6 +263,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()`. /// @@ -889,6 +914,24 @@ 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`. + /// If the `map` call is intentional, this should be rewritten. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// let _ = (0..3).map(|x| x + 2).count(); + /// ``` + pub SUSPICIOUS_MAP, + complexity, + "suspicious usage of map" +} + declare_lint_pass!(Methods => [ OPTION_UNWRAP_USED, RESULT_UNWRAP_USED, @@ -900,6 +943,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, @@ -927,6 +971,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 { @@ -948,6 +993,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]), @@ -972,6 +1018,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), _ => {}, } @@ -1516,30 +1563,30 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp if is_copy(cx, ty) { let snip; if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) { + let parent = cx.tcx.hir().get_parent_node(expr.hir_id); + match &cx.tcx.hir().get(parent) { + hir::Node::Expr(parent) => match parent.node { + // &*x is a nop, &x.clone() is not + hir::ExprKind::AddrOf(..) | + // (*x).func() is useless, x.clone().func() can work in case func borrows mutably + hir::ExprKind::MethodCall(..) => return, + _ => {}, + }, + hir::Node::Stmt(stmt) => { + if let hir::StmtKind::Local(ref loc) = stmt.node { + if let hir::PatKind::Ref(..) = loc.pat.node { + // let ref y = *x borrows x, let ref y = x.clone() does not + return; + } + } + }, + _ => {}, + } + // x.clone() might have dereferenced x, possibly through Deref impls if cx.tables.expr_ty(arg) == ty { snip = Some(("try removing the `clone` call", format!("{}", snippet))); } else { - let parent = cx.tcx.hir().get_parent_node(expr.hir_id); - match cx.tcx.hir().get(parent) { - hir::Node::Expr(parent) => match parent.node { - // &*x is a nop, &x.clone() is not - hir::ExprKind::AddrOf(..) | - // (*x).func() is useless, x.clone().func() can work in case func borrows mutably - hir::ExprKind::MethodCall(..) => return, - _ => {}, - }, - hir::Node::Stmt(stmt) => { - if let hir::StmtKind::Local(ref loc) = stmt.node { - if let hir::PatKind::Ref(..) = loc.pat.node { - // let ref y = *x borrows x, let ref y = x.clone() does not - return; - } - } - }, - _ => {}, - } - let deref_count = cx .tables .expr_adjustments(arg) @@ -1635,13 +1682,12 @@ fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) { } } -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, source: &hir::Expr, unwrap: &hir::Expr) { if_chain! { - if let hir::ExprKind::Call(ref fun, ref args) = new.node; - if args.len() == 1; - if let hir::ExprKind::Path(ref path) = fun.node; - if let Res::Def(DefKind::Method, did) = cx.tables.qpath_res(path, fun.hir_id); - if match_def_path(cx, did, &paths::CSTRING_NEW); + let source_type = cx.tables.expr_ty(source); + if let ty::Adt(def, substs) = source_type.sty; + if match_def_path(cx, def.did, &paths::RESULT); + if match_type(cx, substs.type_at(0), &paths::CSTRING); then { span_lint_and_then( cx, @@ -2067,6 +2113,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 inner_expr.span.from_expansion() { + 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 @@ -2534,6 +2671,16 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_ } } +fn lint_suspicious_map(cx: &LateContext<'_, '_>, expr: &hir::Expr) { + span_help_and_lint( + cx, + SUSPICIOUS_MAP, + expr.span, + "this call to `map()` won't have an effect on the call to `count()`", + "make sure you did not confuse `map` with `filter`", + ); +} + /// Given a `Result` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option> { if let ty::Adt(_, substs) = ty.sty { diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index a127431e2d53..362eaea3c1f8 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -12,8 +12,8 @@ use syntax::source_map::{ExpnKind, Span}; 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_or_desugar, is_integer_literal, - iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, + get_item_name, get_parent_expr, implements_trait, in_constant, is_integer_literal, iter_input_pats, + last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq, }; @@ -641,7 +641,7 @@ fn in_attributes_expansion(expr: &Expr) -> bool { /// Tests whether `res` is a variable defined outside a macro. fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool { if let def::Res::Local(id) = res { - !in_macro_or_desugar(cx.tcx.hir().span(id)) + !cx.tcx.hir().span(id).from_expansion() } else { false } diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs index b998d3f8a331..c8ac26044ebc 100644 --- a/clippy_lints/src/misc_early.rs +++ b/clippy_lints/src/misc_early.rs @@ -1,4 +1,6 @@ -use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then}; +use crate::utils::{ + constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, +}; use if_chain::if_chain; use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; @@ -396,11 +398,18 @@ impl MiscEarlyLints { if char::to_digit(firstch, 10).is_some(); then { let mut prev = '\0'; - for ch in src.chars() { + for (idx, ch) in src.chars().enumerate() { if ch == 'i' || ch == 'u' { if prev != '_' { - span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span, - "integer type suffix should be separated by an underscore"); + span_lint_and_sugg( + cx, + UNSEPARATED_LITERAL_SUFFIX, + lit.span, + "integer type suffix should be separated by an underscore", + "add an underscore", + format!("{}_{}", &src[0..idx], &src[idx..]), + Applicability::MachineApplicable, + ); } break; } @@ -451,11 +460,18 @@ impl MiscEarlyLints { if char::to_digit(firstch, 10).is_some(); then { let mut prev = '\0'; - for ch in src.chars() { + for (idx, ch) in src.chars().enumerate() { if ch == 'f' { if prev != '_' { - span_lint(cx, UNSEPARATED_LITERAL_SUFFIX, lit.span, - "float type suffix should be separated by an underscore"); + span_lint_and_sugg( + cx, + UNSEPARATED_LITERAL_SUFFIX, + lit.span, + "float type suffix should be separated by an underscore", + "add an underscore", + format!("{}_{}", &src[0..idx], &src[idx..]), + Applicability::MachineApplicable, + ); } break; } diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 15cbdf7180d7..6c575fd94a87 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -5,7 +5,7 @@ // [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 // -use crate::utils::{in_macro_or_desugar, span_lint}; +use crate::utils::span_lint; use if_chain::if_chain; use rustc::hir; use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass}; @@ -85,7 +85,7 @@ impl MissingDoc { return; } - if in_macro_or_desugar(sp) { + if sp.from_expansion() { return; } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 285ec0d081f3..7d28b32c3299 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, in_macro_or_desugar, span_lint, span_lint_and_sugg}; +use crate::utils::{higher, span_lint, span_lint_and_sugg}; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; @@ -129,7 +129,7 @@ declare_lint_pass!(BoolComparison => [BOOL_COMPARISON]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if in_macro_or_desugar(e.span) { + if e.span.from_expansion() { return; } diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index b15f836bb1ee..3a0b6d0fbdf0 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -2,7 +2,7 @@ //! //! This lint is **warn** by default -use crate::utils::{in_macro_or_desugar, snippet_opt, span_lint_and_then}; +use crate::utils::{snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc::hir::{BindingAnnotation, Expr, ExprKind, HirId, Item, MutImmutable, Pat, PatKind}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -38,7 +38,7 @@ impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - if in_macro_or_desugar(e.span) || self.derived_item.is_some() { + if e.span.from_expansion() || self.derived_item.is_some() { return; } if let ExprKind::AddrOf(MutImmutable, ref inner) = e.node { @@ -76,7 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow { } } fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) { - if in_macro_or_desugar(pat.span) || self.derived_item.is_some() { + if pat.span.from_expansion() || self.derived_item.is_some() { return; } if_chain! { diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index b6598ac55b38..714c746f68d6 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -2,7 +2,7 @@ //! //! This lint is **warn** by default -use crate::utils::{in_macro_or_desugar, snippet, span_lint_and_then}; +use crate::utils::{snippet, span_lint_and_then}; use if_chain::if_chain; use rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -54,7 +54,7 @@ declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef { fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) { - if in_macro_or_desugar(pat.span) { + if pat.span.from_expansion() { // OK, simple enough, lints doesn't check in macro. return; } diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs index a5c0652b265b..79da82ae3e20 100644 --- a/clippy_lints/src/needless_continue.rs +++ b/clippy_lints/src/needless_continue.rs @@ -39,7 +39,7 @@ use std::borrow::Cow; use syntax::ast; use syntax::source_map::{original_sp, DUMMY_SP}; -use crate::utils::{in_macro_or_desugar, snippet, snippet_block, span_help_and_lint, trim_multiline}; +use crate::utils::{snippet, snippet_block, span_help_and_lint, trim_multiline}; declare_clippy_lint! { /// **What it does:** The lint checks for `if`-statements appearing in loops @@ -120,7 +120,7 @@ declare_lint_pass!(NeedlessContinue => [NEEDLESS_CONTINUE]); impl EarlyLintPass for NeedlessContinue { fn check_expr(&mut self, ctx: &EarlyContext<'_>, expr: &ast::Expr) { - if !in_macro_or_desugar(expr.span) { + if !expr.span.from_expansion() { check_and_warn(ctx, expr); } } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index eaca9c42afb9..f09fb22f82ad 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,7 +1,7 @@ use crate::utils::ptr::get_spans; use crate::utils::{ - get_trait_def_id, implements_trait, in_macro_or_desugar, is_copy, is_self, match_type, multispan_sugg, paths, - snippet, snippet_opt, span_lint_and_then, + get_trait_def_id, implements_trait, is_copy, is_self, match_type, multispan_sugg, paths, snippet, snippet_opt, + span_lint_and_then, }; use if_chain::if_chain; use matches::matches; @@ -76,7 +76,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { span: Span, hir_id: HirId, ) { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 2fe866a1d95b..078aa6923f2d 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,4 +1,4 @@ -use crate::utils::{has_drop, in_macro_or_desugar, snippet_opt, span_lint, span_lint_and_sugg}; +use crate::utils::{has_drop, snippet_opt, span_lint, span_lint_and_sugg}; use rustc::hir::def::{DefKind, Res}; use rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -43,7 +43,7 @@ declare_clippy_lint! { } fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return false; } match expr.node { @@ -103,7 +103,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoEffect { } else if let Some(reduced) = reduce_expression(cx, expr) { let mut snippet = String::new(); for e in reduced { - if in_macro_or_desugar(e.span) { + if e.span.from_expansion() { return; } if let Some(snip) = snippet_opt(cx, e.span) { @@ -128,7 +128,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoEffect { } fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option> { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return None; } match expr.node { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 644660100b8b..56922c73110b 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -14,7 +14,7 @@ use rustc_errors::Applicability; use rustc_typeck::hir_ty_to_ty; use syntax_pos::{InnerSpan, Span, DUMMY_SP}; -use crate::utils::{in_constant, in_macro_or_desugar, is_copy, span_lint_and_then}; +use crate::utils::{in_constant, is_copy, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for declaration of `const` items which is interior @@ -119,7 +119,7 @@ fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, source: S let (lint, msg, span) = source.lint(); span_lint_and_then(cx, lint, span, msg, |db| { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; // Don't give suggestions into macros. } match source { diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index c52b59653706..8e57b8ed7785 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,4 +1,4 @@ -use crate::utils::{in_macro_or_desugar, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; use rustc_errors::Applicability; @@ -32,7 +32,7 @@ declare_lint_pass!(Precedence => [PRECEDENCE]); impl EarlyLintPass for Precedence { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 76f3f8fd88fe..68bf1febc6d6 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -1,6 +1,6 @@ use crate::utils::{ - has_drop, in_macro_or_desugar, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir, - span_lint_hir_and_then, walk_ptrs_ty_depth, + has_drop, is_copy, match_def_path, match_type, paths, snippet_opt, span_lint_hir, span_lint_hir_and_then, + walk_ptrs_ty_depth, }; use if_chain::if_chain; use matches::matches; @@ -91,7 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone { for (bb, bbdata) in mir.basic_blocks().iter_enumerated() { let terminator = bbdata.terminator(); - if in_macro_or_desugar(terminator.source_info.span) { + if terminator.source_info.span.from_expansion() { continue; } diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs index ce33ebf87ba6..68862f838cb0 100644 --- a/clippy_lints/src/redundant_pattern_matching.rs +++ b/clippy_lints/src/redundant_pattern_matching.rs @@ -90,8 +90,8 @@ fn find_sugg_for_if_let<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, db.span_suggestion( span, "try this", - format!("if {}.{}", snippet(cx, op.span, "_"), good_method), - Applicability::MachineApplicable, // snippet + format!("{}.{}", snippet(cx, op.span, "_"), good_method), + Applicability::MaybeIncorrect, // snippet ); }, ); @@ -154,7 +154,7 @@ fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, o span, "try this", format!("{}.{}", snippet(cx, op.span, "_"), good_method), - Applicability::MachineApplicable, // snippet + Applicability::MaybeIncorrect, // snippet ); }, ); diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs index 4d9fbbca83ed..6a1ef19dd6cd 100644 --- a/clippy_lints/src/redundant_static_lifetimes.rs +++ b/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,4 +1,4 @@ -use crate::utils::{in_macro_or_desugar, snippet, span_lint_and_then}; +use crate::utils::{snippet, span_lint_and_then}; use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; use rustc_errors::Applicability; @@ -78,7 +78,7 @@ impl RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !in_macro_or_desugar(item.span) { + if !item.span.from_expansion() { if let ItemKind::Const(ref var_type, _) = item.node { self.visit_type(var_type, cx, "Constants have by default a `'static` lifetime"); // Don't check associated consts because `'static` cannot be elided on those (issue diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 8a8133bfa1ea..3cc053a0ebf6 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -7,7 +7,7 @@ use syntax::source_map::Span; use syntax::visit::FnKind; use syntax_pos::BytePos; -use crate::utils::{in_macro_or_desugar, match_path_ast, snippet_opt, span_lint_and_then}; +use crate::utils::{match_path_ast, snippet_opt, span_lint_and_then}; declare_clippy_lint! { /// **What it does:** Checks for return statements at the end of a block. @@ -155,7 +155,7 @@ impl Return { ) { match inner_span { Some(inner_span) => { - if in_external_macro(cx.sess(), inner_span) || in_macro_or_desugar(inner_span) { + if in_external_macro(cx.sess(), inner_span) || inner_span.from_expansion() { return; } @@ -245,7 +245,7 @@ impl EarlyLintPass for Return { if_chain! { if let ast::FunctionRetTy::Ty(ref ty) = decl.output; if let ast::TyKind::Tup(ref vals) = ty.node; - if vals.is_empty() && !in_macro_or_desugar(ty.span) && get_def(span) == get_def(ty.span); + if vals.is_empty() && !ty.span.from_expansion() && get_def(span) == get_def(ty.span); then { let (rspan, appl) = if let Ok(fn_source) = cx.sess().source_map() @@ -277,7 +277,7 @@ impl EarlyLintPass for Return { if_chain! { if let Some(ref stmt) = block.stmts.last(); if let ast::StmtKind::Expr(ref expr) = stmt.node; - if is_unit_expr(expr) && !in_macro_or_desugar(expr.span); + if is_unit_expr(expr) && !expr.span.from_expansion(); then { let sp = expr.span; span_lint_and_then(cx, UNUSED_UNIT, sp, "unneeded unit expression", |db| { @@ -295,7 +295,7 @@ impl EarlyLintPass for Return { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { match e.node { ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { - if is_unit_expr(expr) && !in_macro_or_desugar(expr.span) { + if is_unit_expr(expr) && !expr.span.from_expansion() { span_lint_and_then(cx, UNUSED_UNIT, expr.span, "unneeded `()`", |db| { db.span_suggestion( expr.span, diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 0de63b5ff3e5..4135fc87fcd1 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -145,7 +145,7 @@ declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { - use crate::utils::{in_macro_or_desugar, snippet, snippet_with_applicability}; + use crate::utils::{snippet, snippet_with_applicability}; use syntax::ast::{LitKind, StrStyle}; if let ExprKind::MethodCall(ref path, _, ref args) = e.node { @@ -177,7 +177,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { } else if callsite == expanded && lit_content.as_str().chars().all(|c| c.is_ascii()) && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT - && !in_macro_or_desugar(args[0].span) + && !args[0].span.from_expansion() { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index bf4c5d65db63..edb91d617ee4 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// pub fn foo(t: T) where T: Copy + Clone {} /// ``` pub TYPE_REPETITION_IN_BOUNDS, - complexity, + pedantic, "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" } diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index be79fc2fb81f..eb6e46c3014e 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -1,6 +1,6 @@ use std::cmp; -use crate::utils::{in_macro_or_desugar, is_copy, is_self_ty, snippet, span_lint_and_sugg}; +use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg}; use if_chain::if_chain; use matches::matches; use rustc::hir; @@ -127,7 +127,7 @@ impl_lint_pass!(TriviallyCopyPassByRef => [TRIVIALLY_COPY_PASS_BY_REF]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef { fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { - if in_macro_or_desugar(item.span) { + if item.span.from_expansion() { return; } @@ -145,7 +145,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef { span: Span, hir_id: HirId, ) { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 7eba331ae0f3..4d9934cee30a 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,4 +1,4 @@ -use crate::utils::{in_macro_or_desugar, match_qpath, paths, snippet, snippet_with_macro_callsite, span_lint_and_sugg}; +use crate::utils::{match_qpath, paths, snippet, snippet_with_macro_callsite, span_lint_and_sugg}; use if_chain::if_chain; use rustc::hir::*; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -67,7 +67,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TryErr { then { let err_type = cx.tables.expr_ty(err_arg); - let origin_snippet = if in_macro_or_desugar(err_arg.span) { + let origin_snippet = if err_arg.span.from_expansion() { snippet_with_macro_callsite(cx, err_arg.span, "_") } else { snippet(cx, err_arg.span, "_") diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6c184246c10a..24eba166c7b1 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -23,8 +23,8 @@ use syntax::symbol::sym; use crate::consts::{constant, Constant}; use crate::utils::paths; use crate::utils::{ - clip, comparisons, differing_macro_contexts, higher, in_constant, in_macro_or_desugar, int_bits, last_path_segment, - match_def_path, match_path, multispan_sugg, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, + clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, last_path_segment, match_def_path, + match_path, multispan_sugg, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, unsext, }; @@ -234,7 +234,7 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str]) /// local bindings should only be checked for the `BORROWED_BOX` lint. #[allow(clippy::too_many_lines)] fn check_ty(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool) { - if in_macro_or_desugar(hir_ty.span) { + if hir_ty.span.from_expansion() { return; } match hir_ty.node { @@ -462,7 +462,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnitValue { fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { if let StmtKind::Local(ref local) = stmt.node { if is_unit(cx.tables.pat_ty(&local.pat)) { - if in_external_macro(cx.sess(), stmt.span) || in_macro_or_desugar(local.pat.span) { + if in_external_macro(cx.sess(), stmt.span) || local.pat.span.from_expansion() { return; } if higher::is_from_for_desugar(local) { @@ -526,7 +526,7 @@ declare_lint_pass!(UnitCmp => [UNIT_CMP]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } if let ExprKind::Binary(ref cmp, ref left, _) = expr.node { @@ -575,7 +575,7 @@ declare_lint_pass!(UnitArg => [UNIT_ARG]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } @@ -1115,7 +1115,7 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { return; } if let ExprKind::Cast(ref ex, _) = expr.node { @@ -1381,7 +1381,7 @@ impl<'a, 'tcx> TypeComplexity { } fn check_type(&self, cx: &LateContext<'_, '_>, ty: &hir::Ty) { - if in_macro_or_desugar(ty.span) { + if ty.span.from_expansion() { return; } let score = { @@ -1485,7 +1485,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 { if let ExprKind::Cast(ref e, _) = expr.node { if let ExprKind::Lit(ref l) = e.node { if let LitKind::Char(_) = l.node { - if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).sty && !in_macro_or_desugar(expr.span) { + if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).sty && !expr.span.from_expansion() { let msg = "casting character literal to u8. `char`s \ are 4 bytes wide in rust, so casting to u8 \ truncates them"; @@ -1646,7 +1646,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons { if let ExprKind::Binary(ref cmp, ref lhs, ref rhs) = expr.node { if let Some((culprit, result)) = detect_absurd_comparison(cx, cmp.node, lhs, rhs) { - if !in_macro_or_desugar(expr.span) { + if !expr.span.from_expansion() { let msg = "this comparison involving the minimum or maximum element for this \ type contains a case that is always true or always false"; diff --git a/clippy_lints/src/unused_label.rs b/clippy_lints/src/unused_label.rs index 9c02c1c31042..197b9a8146ed 100644 --- a/clippy_lints/src/unused_label.rs +++ b/clippy_lints/src/unused_label.rs @@ -1,4 +1,4 @@ -use crate::utils::{in_macro_or_desugar, span_lint}; +use crate::utils::span_lint; use rustc::hir; use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; @@ -44,7 +44,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel { span: Span, fn_id: hir::HirId, ) { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index d39c341d06e5..061d4aa7460c 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -2,9 +2,7 @@ use if_chain::if_chain; use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use rustc::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{ - higher::if_block, in_macro_or_desugar, match_type, paths, span_lint_and_then, usage::is_potentially_mutated, -}; +use crate::utils::{higher::if_block, match_type, paths, span_lint_and_then, usage::is_potentially_mutated}; use rustc::hir::intravisit::*; use rustc::hir::*; use syntax::source_map::Span; @@ -197,7 +195,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unwrap { span: Span, fn_id: HirId, ) { - if in_macro_or_desugar(span) { + if span.from_expansion() { return; } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 020068d4633a..2d772d77ed10 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -92,11 +92,6 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool { } } -/// Returns `true` if this `span` was expanded by any macro or desugaring -pub fn in_macro_or_desugar(span: Span) -> bool { - span.from_expansion() -} - /// Returns `true` if this `span` was expanded by any macro. pub fn in_macro(span: Span) -> bool { if span.from_expansion() { @@ -349,7 +344,7 @@ pub fn method_calls(expr: &Expr, max_depth: usize) -> (Vec, Vec<&[Expr]> let mut current = expr; for _ in 0..max_depth { if let ExprKind::MethodCall(path, _, args) = ¤t.node { - if args.iter().any(|e| in_macro_or_desugar(e.span)) { + if args.iter().any(|e| e.span.from_expansion()) { break; } method_names.push(path.ident.name); @@ -376,7 +371,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option first if let ExprKind::MethodCall(ref path, _, ref args) = current.node { if path.ident.name.as_str() == *method_name { - if args.iter().any(|e| in_macro_or_desugar(e.span)) { + if args.iter().any(|e| e.span.from_expansion()) { return None; } matched.push(&**args); // build up `matched` backwards @@ -471,7 +466,7 @@ pub fn snippet_with_applicability<'a, T: LintContext>( default: &'a str, applicability: &mut Applicability, ) -> Cow<'a, str> { - if *applicability != Applicability::Unspecified && in_macro_or_desugar(span) { + if *applicability != Applicability::Unspecified && span.from_expansion() { *applicability = Applicability::MaybeIncorrect; } snippet_opt(cx, span).map_or_else( @@ -536,7 +531,7 @@ pub fn last_line_of_span(cx: &T, span: Span) -> Span { pub fn expr_block<'a, T: LintContext>(cx: &T, expr: &Expr, option: Option, default: &'a str) -> Cow<'a, str> { let code = snippet_block(cx, expr.span, default); let string = option.unwrap_or_default(); - if in_macro_or_desugar(expr.span) { + if expr.span.from_expansion() { Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) } else if let ExprKind::Block(_, _) = expr.node { Cow::Owned(format!("{}{}", code, string)) diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index be811da02179..5c688a601cd8 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -17,7 +17,7 @@ pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; 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_NEW: [&str; 5] = ["std", "ffi", "c_str", "CString", "new"]; +pub const CSTRING: [&str; 4] = ["std", "ffi", "c_str", "CString"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"]; pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"]; diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 0e45750e94df..b1b5791b15d8 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -1,7 +1,7 @@ //! Contains utility functions to generate suggestions. #![deny(clippy::missing_docs_in_private_items)] -use crate::utils::{higher, in_macro_or_desugar, snippet, snippet_opt, snippet_with_macro_callsite}; +use crate::utils::{higher, snippet, snippet_opt, snippet_with_macro_callsite}; use matches::matches; use rustc::hir; use rustc::lint::{EarlyContext, LateContext, LintContext}; @@ -69,7 +69,7 @@ impl<'a> Sugg<'a> { default: &'a str, applicability: &mut Applicability, ) -> Self { - if *applicability != Applicability::Unspecified && in_macro_or_desugar(expr.span) { + if *applicability != Applicability::Unspecified && expr.span.from_expansion() { *applicability = Applicability::MaybeIncorrect; } Self::hir_opt(cx, expr).unwrap_or_else(|| { diff --git a/doc/adding_lints.md b/doc/adding_lints.md index d87580191fb9..c9816911a828 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -392,7 +392,7 @@ Here are some pointers to things you are likely going to need for every lint: is already in here (`implements_trait`, `match_path`, `snippet`, etc) * [Clippy diagnostics][diagnostics] * [The `if_chain` macro][if_chain] -* [`in_macro_or_desugar`][in_macro_or_desugar] and [`in_external_macro`][in_external_macro] +* [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro] * [`Span`][span] * [`Applicability`][applicability] * [The rustc guide][rustc_guide] explains a lot of internal compiler concepts @@ -429,10 +429,10 @@ don't hesitate to ask on Discord, IRC or in the issue/PR. [ident]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/source_map/symbol/struct.Ident.html [span]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax_pos/struct.Span.html [applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html -[if_chain]: https://docs.rs/if_chain/0.1.2/if_chain/ +[if_chain]: https://docs.rs/if_chain/*/if_chain/ [ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty/sty/index.html [ast]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/index.html -[in_macro_or_desugar]: https://github.com/rust-lang/rust-clippy/blob/d0717d1f9531a03d154aaeb0cad94c243915a146/clippy_lints/src/utils/mod.rs#L94 +[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax_pos/struct.Span.html#method.from_expansion [in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/fn.in_external_macro.html [play]: https://play.rust-lang.org [author_example]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f093b986e80ad62f3b67a1f24f5e66e2 diff --git a/doc/changelog_update.md b/doc/changelog_update.md new file mode 100644 index 000000000000..cabf25135dac --- /dev/null +++ b/doc/changelog_update.md @@ -0,0 +1,68 @@ +# Changelog Update + +If you want to help with updating the [changelog][changelog], you're in the right place. + +## When to update + +Typos and other small fixes/additions are _always_ welcome. + +Special care needs to be taken when it comes to updating the changelog for a new +Rust release. For that purpose, the changelog is ideally updated during the week +before an upcoming stable release. You can find the release dates on the [Rust +Forge][forge]. + +Most of the time we only need to update the changelog for minor Rust releases. It's +been very rare that Clippy changes were included in a patch release. + +## How to update + +### 1. Finding the relevant Clippy commits + +Each Rust release ships with its own version of Clippy. The Clippy submodule can +be found in the [tools][tools] directory of the Rust repository. + +To find the Clippy commit hash for a specific Rust release you select the Rust +release tag from the dropdown and then check the commit of the Clippy directory: + +![Explanation of how to find the commit hash](https://user-images.githubusercontent.com/2042399/62846160-1f8b0480-bcce-11e9-9da8-7964ca034e7a.png) + +When writing the release notes for the upcoming stable release you want to check +out the commit of the current Rust `beta` tag. + +### 2. Fetching the PRs between those commits + +You'll want to run `util/fetch_prs_between.sh commit1 commit2 > changes.txt` +and open that file in your editor of choice. + +* `commit1` is the Clippy commit hash of the previous stable release +* `commit2` is the Clippy commit hash of the release you want to write the changelog for. + +When updating the changelog it's also a good idea to make sure that `commit1` is +already correct in the current changelog. + +### 3. Authoring the final changelog + +The above script should have dumped all the relevant PRs to the file you +specified. It should have filtered out most of the irrelevant PRs +already, but it's a good idea to do a manual cleanup pass where you look for +more irrelevant PRs. If you're not sure about some PRs, just leave them in for +the review and ask for feedback. + +With the PRs filtered, you can start to take each PR and move the +`changelog: ` content to `CHANGELOG.md`. Adapt the wording as you see fit but +try to keep it somewhat coherent. + +The order should roughly be: + +1. New lints +2. Changes that expand what code existing lints cover +3. ICE fixes +4. False positive fixes +5. Suggestion fixes/improvements + +Please also be sure to update the Beta/Unreleased sections at the top with the +relevant commit ranges. + +[changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md +[forge]: https://forge.rust-lang.org/ +[tools]: https://github.com/rust-lang/rust/tree/master/src/tools diff --git a/src/driver.rs b/src/driver.rs index cec88be7eb1b..92f83f1a29e3 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 86174a6b316f..76e1c711656b 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<'_>) { diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 0df8370936c8..9abe4558bb91 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; 311] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -1316,6 +1316,13 @@ pub const ALL_LINTS: [Lint; 309] = [ 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", @@ -1736,6 +1743,13 @@ pub const ALL_LINTS: [Lint; 309] = [ deprecation: None, module: "formatting", }, + Lint { + name: "suspicious_map", + group: "complexity", + desc: "suspicious usage of map", + deprecation: None, + module: "methods", + }, Lint { name: "suspicious_op_assign_impl", group: "correctness", @@ -1857,7 +1871,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", diff --git a/tests/ui/cstring.rs b/tests/ui/cstring.rs index 0d775d4067a3..6cdd6b4ff6e7 100644 --- a/tests/ui/cstring.rs +++ b/tests/ui/cstring.rs @@ -1,9 +1,24 @@ +#![deny(clippy::temporary_cstring_as_ptr)] + fn main() {} -#[allow(clippy::result_unwrap_used)] fn temporary_cstring() { use std::ffi::CString; CString::new("foo").unwrap().as_ptr(); CString::new("foo").expect("dummy").as_ptr(); } + +mod issue4375 { + use std::ffi::CString; + use std::os::raw::c_char; + + extern "C" { + fn foo(data: *const c_char); + } + + pub fn bar(v: &[u8]) { + let cstr = CString::new(v); + unsafe { foo(cstr.unwrap().as_ptr()) } + } +} diff --git a/tests/ui/cstring.stderr b/tests/ui/cstring.stderr index 83f64ff3b026..21838237413c 100644 --- a/tests/ui/cstring.stderr +++ b/tests/ui/cstring.stderr @@ -1,29 +1,46 @@ error: you are getting the inner pointer of a temporary `CString` - --> $DIR/cstring.rs:7:5 + --> $DIR/cstring.rs:8:5 | LL | CString::new("foo").unwrap().as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[deny(clippy::temporary_cstring_as_ptr)]` on by default +note: lint level defined here + --> $DIR/cstring.rs:1:9 + | +LL | #![deny(clippy::temporary_cstring_as_ptr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: that pointer will be invalid outside this expression help: assign the `CString` to a variable to extend its lifetime - --> $DIR/cstring.rs:7:5 + --> $DIR/cstring.rs:8:5 | LL | CString::new("foo").unwrap().as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: you are getting the inner pointer of a temporary `CString` - --> $DIR/cstring.rs:8:5 + --> $DIR/cstring.rs:9:5 | LL | CString::new("foo").expect("dummy").as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: that pointer will be invalid outside this expression help: assign the `CString` to a variable to extend its lifetime - --> $DIR/cstring.rs:8:5 + --> $DIR/cstring.rs:9:5 | LL | CString::new("foo").expect("dummy").as_ptr(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: you are getting the inner pointer of a temporary `CString` + --> $DIR/cstring.rs:22:22 + | +LL | unsafe { foo(cstr.unwrap().as_ptr()) } + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: that pointer will be invalid outside this expression +help: assign the `CString` to a variable to extend its lifetime + --> $DIR/cstring.rs:22:22 + | +LL | unsafe { foo(cstr.unwrap().as_ptr()) } + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/issue_4266.rs b/tests/ui/issue_4266.rs index 953879f7bed0..1538abb1d776 100644 --- a/tests/ui/issue_4266.rs +++ b/tests/ui/issue_4266.rs @@ -1,5 +1,4 @@ // compile-flags: --edition 2018 -#![feature(async_await)] #![allow(dead_code)] async fn sink1<'a>(_: &'a str) {} // lint diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index 8b4e70eb9c22..2ebe85bd6b0e 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.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/issue_4266.rs:5:1 + --> $DIR/issue_4266.rs:4:1 | LL | async fn sink1<'a>(_: &'a str) {} // lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | async fn sink1<'a>(_: &'a str) {} // lint = 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/issue_4266.rs:9:1 + --> $DIR/issue_4266.rs:8:1 | LL | / async fn one_to_one<'a>(s: &'a str) -> &'a str { LL | | s diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index 5f3f95bab980..be1d2ed2f4d6 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -1,7 +1,7 @@ #![warn(clippy::large_digit_groups)] #![warn(clippy::mixed_case_hex_literals)] -#![warn(clippy::unseparated_literal_suffix)] #![warn(clippy::zero_prefixed_literal)] +#![allow(clippy::unseparated_literal_suffix)] #![allow(dead_code)] fn main() { @@ -15,15 +15,6 @@ fn main() { let fail2 = 0xabCD_isize; let fail_multi_zero = 000_123usize; - let ok6 = 1234_i32; - let ok7 = 1234_f32; - let ok8 = 1234_isize; - let fail3 = 1234i32; - let fail4 = 1234u32; - let fail5 = 1234isize; - let fail6 = 1234usize; - let fail7 = 1.5f32; - let ok9 = 0; let ok10 = 0_i64; let fail8 = 0123; diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 22692160d73a..4f3d430c4d99 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -18,14 +18,6 @@ error: inconsistent casing in hexadecimal literal LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ -error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:16:27 - | -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:16:27 | @@ -42,38 +34,8 @@ help: if you mean to use an octal constant, use `0o` LL | let fail_multi_zero = 0o123usize; | ^^^^^^^^^^ -error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:21:17 - | -LL | let fail3 = 1234i32; - | ^^^^^^^ - -error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:22:17 - | -LL | let fail4 = 1234u32; - | ^^^^^^^ - -error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:23:17 - | -LL | let fail5 = 1234isize; - | ^^^^^^^^^ - -error: integer type suffix should be separated by an underscore - --> $DIR/literals.rs:24:17 - | -LL | let fail6 = 1234usize; - | ^^^^^^^^^ - -error: float type suffix should be separated by an underscore - --> $DIR/literals.rs:25:17 - | -LL | let fail7 = 1.5f32; - | ^^^^^^ - error: this is a decimal constant - --> $DIR/literals.rs:29:17 + --> $DIR/literals.rs:20:17 | LL | let fail8 = 0123; | ^^^^ @@ -87,7 +49,7 @@ LL | let fail8 = 0o123; | ^^^^^ error: digit groups should be smaller - --> $DIR/literals.rs:40:18 + --> $DIR/literals.rs:31:18 | LL | let fail13 = 0x1_23456_78901_usize; | ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize` @@ -95,7 +57,7 @@ LL | let fail13 = 0x1_23456_78901_usize; = note: `-D clippy::large-digit-groups` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:42:18 + --> $DIR/literals.rs:33:18 | LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` @@ -103,16 +65,16 @@ LL | let fail19 = 12_3456_21; = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:43:18 + --> $DIR/literals.rs:34:18 | LL | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> $DIR/literals.rs:44:18 + --> $DIR/literals.rs:35:18 | LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` -error: aborting due to 15 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 5ae2b32c1bb0..53f9f82485d1 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,7 +1,6 @@ // aux-build:option_helpers.rs // compile-flags: --edition 2018 -#![feature(async_await)] #![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)] #![allow( clippy::blacklisted_name, diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 8d09c49f005b..504bb5e8253f 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:36: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:152: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:174: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:178: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:182: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:187: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:189: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:193: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:204: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:208: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:212: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:216: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:246: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:249: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:13 + --> $DIR/methods.rs:265:13 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,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:269:13 + --> $DIR/methods.rs:268:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -158,7 +158,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:275:13 + --> $DIR/methods.rs:274:13 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,7 +166,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:278:13 + --> $DIR/methods.rs:277:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -176,7 +176,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:284:13 + --> $DIR/methods.rs:283:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,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:287:13 + --> $DIR/methods.rs:286:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -194,7 +194,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:302:13 + --> $DIR/methods.rs:301:13 | LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ diff --git a/tests/ui/option_and_then_some.fixed b/tests/ui/option_and_then_some.fixed new file mode 100644 index 000000000000..035bc1e54656 --- /dev/null +++ b/tests/ui/option_and_then_some.fixed @@ -0,0 +1,25 @@ +// 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 = Ok(1); + let _ = x.and_then(Ok); +} + +pub fn foo() -> Option { + let x = Some(String::from("hello")); + Some("hello".to_owned()).and_then(|s| Some(format!("{}{}", s, x?))) +} + +pub fn example2(x: bool) -> Option<&'static str> { + Some("a").and_then(|s| Some(if x { s } else { return None })) +} diff --git a/tests/ui/option_and_then_some.rs b/tests/ui/option_and_then_some.rs new file mode 100644 index 000000000000..d49da7813c6e --- /dev/null +++ b/tests/ui/option_and_then_some.rs @@ -0,0 +1,25 @@ +// 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 = Ok(1); + let _ = x.and_then(Ok); +} + +pub fn foo() -> Option { + let x = Some(String::from("hello")); + Some("hello".to_owned()).and_then(|s| Some(format!("{}{}", s, x?))) +} + +pub fn example2(x: bool) -> Option<&'static str> { + Some("a").and_then(|s| Some(if x { s } else { return None })) +} diff --git a/tests/ui/option_and_then_some.stderr b/tests/ui/option_and_then_some.stderr new file mode 100644 index 000000000000..a3b0a26149e1 --- /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 + diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed index e637f973c2ea..decbae4e5af9 100644 --- a/tests/ui/option_map_or_none.fixed +++ b/tests/ui/option_map_or_none.fixed @@ -1,5 +1,7 @@ // run-rustfix +#![allow(clippy::option_and_then_some)] + fn main() { let opt = Some(1); diff --git a/tests/ui/option_map_or_none.rs b/tests/ui/option_map_or_none.rs index 4b9b247880a0..0f1d2218d5d3 100644 --- a/tests/ui/option_map_or_none.rs +++ b/tests/ui/option_map_or_none.rs @@ -1,5 +1,7 @@ // run-rustfix +#![allow(clippy::option_and_then_some)] + fn main() { let opt = Some(1); diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 66ed1e9f0451..eb5c68ed79f3 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,5 +1,5 @@ error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/option_map_or_none.rs:8:13 + --> $DIR/option_map_or_none.rs:10:13 | LL | let _ = opt.map_or(None, |x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using and_then instead: `opt.and_then(|x| Some(x + 1))` @@ -7,7 +7,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/option_map_or_none.rs:11:13 + --> $DIR/option_map_or_none.rs:13:13 | LL | let _ = opt.map_or(None, |x| { | _____________^ diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 8e8d4b59ba4e..2bea7d8d9618 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -1,5 +1,6 @@ #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] +#![allow(clippy::unit_arg, clippy::let_unit_value)] fn main() { if let Ok(_) = Ok::(42) {} @@ -51,4 +52,39 @@ fn main() { Some(_) => false, None => true, }; + + let _ = match None::<()> { + Some(_) => false, + None => true, + }; + + let _ = if let Ok(_) = Ok::(4) { true } else { false }; + + let _ = does_something(); + let _ = returns_unit(); + + let opt = Some(false); + let x = if let Some(_) = opt { true } else { false }; + takes_bool(x); + let y = if let Some(_) = opt {}; + takes_unit(y); +} + +fn takes_bool(x: bool) {} +fn takes_unit(x: ()) {} + +fn does_something() -> bool { + if let Ok(_) = Ok::(4) { + true + } else { + false + } +} + +fn returns_unit() { + if let Ok(_) = Ok::(4) { + true + } else { + false + }; } diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index baed95d6f2e7..df12b7e169a1 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -1,31 +1,31 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:5:12 + --> $DIR/redundant_pattern_matching.rs:6:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^------------------------ help: try this: `if Ok::(42).is_ok()` + | -------^^^^^------------------------ help: try this: `Ok::(42).is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:7:12 + --> $DIR/redundant_pattern_matching.rs:8:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^------------------------- help: try this: `if Err::(42).is_err()` + | -------^^^^^^------------------------- help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching.rs:9:12 + --> $DIR/redundant_pattern_matching.rs:10:12 | LL | if let None = None::<()> {} - | -------^^^^---------------- help: try this: `if None::<()>.is_none()` + | -------^^^^---------------- help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:11:12 + --> $DIR/redundant_pattern_matching.rs:12:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^-------------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^-------------- help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:25:5 + --> $DIR/redundant_pattern_matching.rs:26:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -34,7 +34,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:30:5 + --> $DIR/redundant_pattern_matching.rs:31:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -43,7 +43,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:35:5 + --> $DIR/redundant_pattern_matching.rs:36:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:40:5 + --> $DIR/redundant_pattern_matching.rs:41:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:45:5 + --> $DIR/redundant_pattern_matching.rs:46: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:50:5 + --> $DIR/redundant_pattern_matching.rs:51:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -78,5 +78,55 @@ LL | | None => true, LL | | }; | |_____^ help: try this: `None::<()>.is_none()` -error: aborting due to 10 previous errors +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching.rs:56:13 + | +LL | let _ = match None::<()> { + | _____________^ +LL | | Some(_) => false, +LL | | None => true, +LL | | }; + | |_____^ help: try this: `None::<()>.is_none()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:61:20 + | +LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; + | -------^^^^^--------------------------------------------- help: try this: `Ok::(4).is_ok()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:67:20 + | +LL | let x = if let Some(_) = opt { true } else { false }; + | -------^^^^^^^------------------------------ help: try this: `opt.is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching.rs:69:20 + | +LL | let y = if let Some(_) = opt {}; + | -------^^^^^^^--------- help: try this: `opt.is_some()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:77:12 + | +LL | if let Ok(_) = Ok::(4) { + | _____- ^^^^^ +LL | | true +LL | | } else { +LL | | false +LL | | } + | |_____- help: try this: `Ok::(4).is_ok()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching.rs:85:12 + | +LL | if let Ok(_) = Ok::(4) { + | _____- ^^^^^ +LL | | true +LL | | } else { +LL | | false +LL | | }; + | |_____- help: try this: `Ok::(4).is_ok()` + +error: aborting due to 16 previous errors diff --git a/tests/ui/suspicious_map.rs b/tests/ui/suspicious_map.rs new file mode 100644 index 000000000000..d838d8fde210 --- /dev/null +++ b/tests/ui/suspicious_map.rs @@ -0,0 +1,5 @@ +#![warn(clippy::suspicious_map)] + +fn main() { + let _ = (0..3).map(|x| x + 2).count(); +} diff --git a/tests/ui/suspicious_map.stderr b/tests/ui/suspicious_map.stderr new file mode 100644 index 000000000000..e6588f4691a1 --- /dev/null +++ b/tests/ui/suspicious_map.stderr @@ -0,0 +1,11 @@ +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 + diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 2e0fc1227781..4ff835115909 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -22,6 +22,11 @@ fn clone_on_copy() { let rc = RefCell::new(0); rc.borrow().clone(); + + // Issue #4348 + let mut x = 43; + let _ = &x.clone(); // ok, getting a ref + 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate } fn clone_on_ref_ptr() { diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 79b99ff1d1d2..b1388044c42c 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -19,7 +19,7 @@ LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:34:5 + --> $DIR/unnecessary_clone.rs:39:5 | LL | rc.clone(); | ^^^^^^^^^^ help: try this: `Rc::::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:37:5 + --> $DIR/unnecessary_clone.rs:42:5 | LL | arc.clone(); | ^^^^^^^^^^^ help: try this: `Arc::::clone(&arc)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:40:5 + --> $DIR/unnecessary_clone.rs:45:5 | LL | rcweak.clone(); | ^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&rcweak)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:43:5 + --> $DIR/unnecessary_clone.rs:48:5 | LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` error: using '.clone()' on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:47:33 + --> $DIR/unnecessary_clone.rs:52:33 | LL | let _: Arc = x.clone(); | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:51:5 + --> $DIR/unnecessary_clone.rs:56:5 | LL | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:53:5 + --> $DIR/unnecessary_clone.rs:58: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:59:22 + --> $DIR/unnecessary_clone.rs:64:22 | LL | let z: &Vec<_> = y.clone(); | ^^^^^^^^^ @@ -79,7 +79,7 @@ LL | let z: &Vec<_> = &std::vec::Vec::clone(y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/unnecessary_clone.rs:66:27 + --> $DIR/unnecessary_clone.rs:71:27 | LL | let v2: Vec = v.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` @@ -87,13 +87,13 @@ LL | let v2: Vec = v.iter().cloned().collect(); = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/unnecessary_clone.rs:71:38 + --> $DIR/unnecessary_clone.rs:76:38 | LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/unnecessary_clone.rs:76:24 + --> $DIR/unnecessary_clone.rs:81:24 | LL | .to_bytes() | ________________________^ @@ -103,7 +103,7 @@ LL | | .collect(); | |______________________^ help: try: `.to_vec()` error: using `clone` on a `Copy` type - --> $DIR/unnecessary_clone.rs:114:20 + --> $DIR/unnecessary_clone.rs:119:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` diff --git a/tests/ui/unseparated_prefix_literals.fixed b/tests/ui/unseparated_prefix_literals.fixed new file mode 100644 index 000000000000..1948b18d1639 --- /dev/null +++ b/tests/ui/unseparated_prefix_literals.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +#![warn(clippy::unseparated_literal_suffix)] +#![allow(dead_code)] + +fn main() { + let _ok1 = 1234_i32; + let _ok2 = 1234_isize; + let _ok3 = 0x123_isize; + let _fail1 = 1234_i32; + let _fail2 = 1234_u32; + let _fail3 = 1234_isize; + let _fail4 = 1234_usize; + let _fail5 = 0x123_isize; + + let _okf1 = 1.5_f32; + let _okf2 = 1_f32; + let _failf1 = 1.5_f32; + let _failf2 = 1_f32; +} diff --git a/tests/ui/unseparated_prefix_literals.rs b/tests/ui/unseparated_prefix_literals.rs new file mode 100644 index 000000000000..d70b1cf29f53 --- /dev/null +++ b/tests/ui/unseparated_prefix_literals.rs @@ -0,0 +1,20 @@ +// run-rustfix + +#![warn(clippy::unseparated_literal_suffix)] +#![allow(dead_code)] + +fn main() { + let _ok1 = 1234_i32; + let _ok2 = 1234_isize; + let _ok3 = 0x123_isize; + let _fail1 = 1234i32; + let _fail2 = 1234u32; + let _fail3 = 1234isize; + let _fail4 = 1234usize; + let _fail5 = 0x123isize; + + let _okf1 = 1.5_f32; + let _okf2 = 1_f32; + let _failf1 = 1.5f32; + let _failf2 = 1f32; +} diff --git a/tests/ui/unseparated_prefix_literals.stderr b/tests/ui/unseparated_prefix_literals.stderr new file mode 100644 index 000000000000..2b8121db3fc0 --- /dev/null +++ b/tests/ui/unseparated_prefix_literals.stderr @@ -0,0 +1,46 @@ +error: integer type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:10:18 + | +LL | let _fail1 = 1234i32; + | ^^^^^^^ help: add an underscore: `1234_i32` + | + = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` + +error: integer type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:11:18 + | +LL | let _fail2 = 1234u32; + | ^^^^^^^ help: add an underscore: `1234_u32` + +error: integer type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:12:18 + | +LL | let _fail3 = 1234isize; + | ^^^^^^^^^ help: add an underscore: `1234_isize` + +error: integer type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:13:18 + | +LL | let _fail4 = 1234usize; + | ^^^^^^^^^ help: add an underscore: `1234_usize` + +error: integer type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:14:18 + | +LL | let _fail5 = 0x123isize; + | ^^^^^^^^^^ help: add an underscore: `0x123_isize` + +error: float type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:18:19 + | +LL | let _failf1 = 1.5f32; + | ^^^^^^ help: add an underscore: `1.5_f32` + +error: float type suffix should be separated by an underscore + --> $DIR/unseparated_prefix_literals.rs:19:19 + | +LL | let _failf2 = 1f32; + | ^^^^ help: add an underscore: `1_f32` + +error: aborting due to 7 previous errors +