]> git.lizzy.rs Git - rust.git/commitdiff
Merge remote-tracking branch 'origin/beta_backport' into HEAD
authorManish Goregaokar <manishsmail@gmail.com>
Fri, 17 May 2019 19:53:52 +0000 (12:53 -0700)
committerManish Goregaokar <manishsmail@gmail.com>
Fri, 17 May 2019 19:53:52 +0000 (12:53 -0700)
905 files changed:
.cargo/config [new file with mode: 0644]
.gitattributes [new file with mode: 0644]
.github/ISSUE_TEMPLATE.md
.github/PULL_REQUEST_TEMPLATE [new file with mode: 0644]
.github/deploy.sh
.gitignore
.travis.yml
CHANGELOG.md
CODE_OF_CONDUCT.md [new file with mode: 0644]
CONTRIBUTING.md
COPYRIGHT [new file with mode: 0644]
Cargo.toml
LICENSE [deleted file]
LICENSE-APACHE [new file with mode: 0644]
LICENSE-MIT [new file with mode: 0644]
PUBLISH.md
README.md
appveyor.yml
build.rs
ci/base-tests.sh
ci/integration-tests.sh
clippy_dev/Cargo.toml [new file with mode: 0644]
clippy_dev/src/lib.rs [new file with mode: 0644]
clippy_dev/src/main.rs [new file with mode: 0644]
clippy_dummy/Cargo.toml [new file with mode: 0644]
clippy_dummy/PUBLISH.md [new file with mode: 0644]
clippy_dummy/build.rs [new file with mode: 0644]
clippy_dummy/crates-readme.md [new file with mode: 0644]
clippy_dummy/src/main.rs [new file with mode: 0644]
clippy_lints/Cargo.toml
clippy_lints/README.md
clippy_lints/src/approx_const.rs
clippy_lints/src/arithmetic.rs
clippy_lints/src/assertions_on_constants.rs [new file with mode: 0644]
clippy_lints/src/assign_ops.rs
clippy_lints/src/attrs.rs
clippy_lints/src/bit_mask.rs
clippy_lints/src/blacklisted_name.rs
clippy_lints/src/block_in_if_condition.rs
clippy_lints/src/booleans.rs
clippy_lints/src/bytecount.rs
clippy_lints/src/cargo_common_metadata.rs [new file with mode: 0644]
clippy_lints/src/cognitive_complexity.rs [new file with mode: 0644]
clippy_lints/src/collapsible_if.rs
clippy_lints/src/const_static_lifetime.rs
clippy_lints/src/consts.rs
clippy_lints/src/copies.rs
clippy_lints/src/copy_iterator.rs [new file with mode: 0644]
clippy_lints/src/cyclomatic_complexity.rs [deleted file]
clippy_lints/src/dbg_macro.rs [new file with mode: 0644]
clippy_lints/src/default_trait_access.rs
clippy_lints/src/deprecated_lints.rs
clippy_lints/src/derive.rs
clippy_lints/src/doc.rs
clippy_lints/src/double_comparison.rs
clippy_lints/src/double_parens.rs
clippy_lints/src/drop_bounds.rs [new file with mode: 0644]
clippy_lints/src/drop_forget_ref.rs
clippy_lints/src/duration_subsec.rs
clippy_lints/src/else_if_without_else.rs
clippy_lints/src/empty_enum.rs
clippy_lints/src/entry.rs
clippy_lints/src/enum_clike.rs
clippy_lints/src/enum_glob_use.rs
clippy_lints/src/enum_variants.rs
clippy_lints/src/eq_op.rs
clippy_lints/src/erasing_op.rs
clippy_lints/src/escape.rs
clippy_lints/src/eta_reduction.rs
clippy_lints/src/eval_order_dependence.rs
clippy_lints/src/excessive_precision.rs
clippy_lints/src/explicit_write.rs
clippy_lints/src/fallible_impl_from.rs
clippy_lints/src/format.rs
clippy_lints/src/formatting.rs
clippy_lints/src/functions.rs
clippy_lints/src/identity_conversion.rs
clippy_lints/src/identity_op.rs
clippy_lints/src/if_let_redundant_pattern_matching.rs [deleted file]
clippy_lints/src/if_not_else.rs
clippy_lints/src/implicit_return.rs [new file with mode: 0644]
clippy_lints/src/indexing_slicing.rs
clippy_lints/src/infallible_destructuring_match.rs
clippy_lints/src/infinite_iter.rs
clippy_lints/src/inherent_impl.rs
clippy_lints/src/inline_fn_without_body.rs
clippy_lints/src/int_plus_one.rs
clippy_lints/src/invalid_ref.rs
clippy_lints/src/items_after_statements.rs
clippy_lints/src/large_enum_variant.rs
clippy_lints/src/len_zero.rs
clippy_lints/src/let_if_seq.rs
clippy_lints/src/lib.rs
clippy_lints/src/lifetimes.rs
clippy_lints/src/literal_representation.rs
clippy_lints/src/loops.rs
clippy_lints/src/map_clone.rs
clippy_lints/src/map_unit_fn.rs
clippy_lints/src/matches.rs
clippy_lints/src/mem_discriminant.rs [new file with mode: 0644]
clippy_lints/src/mem_forget.rs
clippy_lints/src/mem_replace.rs [new file with mode: 0644]
clippy_lints/src/methods.rs [deleted file]
clippy_lints/src/methods/mod.rs [new file with mode: 0644]
clippy_lints/src/methods/option_map_unwrap_or.rs [new file with mode: 0644]
clippy_lints/src/methods/unnecessary_filter_map.rs [new file with mode: 0644]
clippy_lints/src/minmax.rs
clippy_lints/src/misc.rs
clippy_lints/src/misc_early.rs
clippy_lints/src/missing_const_for_fn.rs [new file with mode: 0644]
clippy_lints/src/missing_doc.rs
clippy_lints/src/missing_inline.rs
clippy_lints/src/multiple_crate_versions.rs
clippy_lints/src/mut_mut.rs
clippy_lints/src/mut_reference.rs
clippy_lints/src/mutex_atomic.rs
clippy_lints/src/needless_bool.rs
clippy_lints/src/needless_borrow.rs
clippy_lints/src/needless_borrowed_ref.rs
clippy_lints/src/needless_continue.rs
clippy_lints/src/needless_pass_by_value.rs
clippy_lints/src/needless_update.rs
clippy_lints/src/neg_cmp_op_on_partial_ord.rs
clippy_lints/src/neg_multiply.rs
clippy_lints/src/new_without_default.rs
clippy_lints/src/no_effect.rs
clippy_lints/src/non_copy_const.rs
clippy_lints/src/non_expressive_names.rs
clippy_lints/src/ok_if_let.rs
clippy_lints/src/open_options.rs
clippy_lints/src/overflow_check_conditional.rs
clippy_lints/src/panic_unimplemented.rs
clippy_lints/src/partialeq_ne_impl.rs
clippy_lints/src/path_buf_push_overwrite.rs [new file with mode: 0644]
clippy_lints/src/precedence.rs
clippy_lints/src/ptr.rs
clippy_lints/src/ptr_offset_with_cast.rs [new file with mode: 0644]
clippy_lints/src/question_mark.rs
clippy_lints/src/ranges.rs
clippy_lints/src/redundant_clone.rs [new file with mode: 0644]
clippy_lints/src/redundant_field_names.rs
clippy_lints/src/redundant_pattern_matching.rs [new file with mode: 0644]
clippy_lints/src/reference.rs
clippy_lints/src/regex.rs
clippy_lints/src/replace_consts.rs
clippy_lints/src/returns.rs
clippy_lints/src/serde_api.rs
clippy_lints/src/shadow.rs
clippy_lints/src/slow_vector_initialization.rs [new file with mode: 0644]
clippy_lints/src/strings.rs
clippy_lints/src/suspicious_trait_impl.rs
clippy_lints/src/swap.rs
clippy_lints/src/temporary_assignment.rs
clippy_lints/src/transmute.rs
clippy_lints/src/transmuting_null.rs [new file with mode: 0644]
clippy_lints/src/trivially_copy_pass_by_ref.rs
clippy_lints/src/types.rs
clippy_lints/src/unicode.rs
clippy_lints/src/unsafe_removed_from_name.rs
clippy_lints/src/unused_io_amount.rs
clippy_lints/src/unused_label.rs
clippy_lints/src/unwrap.rs
clippy_lints/src/use_self.rs
clippy_lints/src/utils/attrs.rs [new file with mode: 0644]
clippy_lints/src/utils/author.rs
clippy_lints/src/utils/camel_case.rs [new file with mode: 0644]
clippy_lints/src/utils/comparisons.rs
clippy_lints/src/utils/conf.rs
clippy_lints/src/utils/constants.rs
clippy_lints/src/utils/diagnostics.rs [new file with mode: 0644]
clippy_lints/src/utils/higher.rs
clippy_lints/src/utils/hir_utils.rs
clippy_lints/src/utils/inspector.rs
clippy_lints/src/utils/internal_lints.rs
clippy_lints/src/utils/mod.rs
clippy_lints/src/utils/paths.rs
clippy_lints/src/utils/ptr.rs
clippy_lints/src/utils/sugg.rs
clippy_lints/src/utils/sym.rs [new file with mode: 0644]
clippy_lints/src/utils/usage.rs
clippy_lints/src/vec.rs
clippy_lints/src/wildcard_dependencies.rs [new file with mode: 0644]
clippy_lints/src/write.rs
clippy_lints/src/zero_div_zero.rs
clippy_workspace_tests/Cargo.toml
clippy_workspace_tests/src/main.rs
doc/adding_lints.md [new file with mode: 0644]
etc/relicense/RELICENSE_DOCUMENTATION.md [new file with mode: 0644]
etc/relicense/contributors.txt [new file with mode: 0644]
etc/relicense/relicense_comments.txt [new file with mode: 0644]
mini-macro/Cargo.toml
mini-macro/src/lib.rs
pre_publish.sh
rust-update [deleted file]
rustc_tools_util/Cargo.toml [new file with mode: 0644]
rustc_tools_util/README.md [new file with mode: 0644]
rustc_tools_util/src/lib.rs [new file with mode: 0644]
rustfmt.toml
setup-toolchain.sh [new file with mode: 0755]
src/driver.rs
src/lib.rs
src/main.rs
tests/camel_case.rs [deleted file]
tests/compile-test.rs
tests/dogfood.rs
tests/matches.rs
tests/missing-test-files.rs [new file with mode: 0644]
tests/needless_continue_helpers.rs
tests/run-pass/associated-constant-ice.rs [deleted file]
tests/run-pass/cc_seme.rs [deleted file]
tests/run-pass/enum-glob-import-crate.rs [deleted file]
tests/run-pass/ice-1588.rs [deleted file]
tests/run-pass/ice-1782.rs [deleted file]
tests/run-pass/ice-1969.rs [deleted file]
tests/run-pass/ice-2499.rs [deleted file]
tests/run-pass/ice-2594.rs [deleted file]
tests/run-pass/ice-2727.rs [deleted file]
tests/run-pass/ice-2760.rs [deleted file]
tests/run-pass/ice-2774.rs [deleted file]
tests/run-pass/ice-2865.rs [deleted file]
tests/run-pass/ice-700.rs [deleted file]
tests/run-pass/ice_exacte_size.rs [deleted file]
tests/run-pass/if_same_then_else.rs [deleted file]
tests/run-pass/issue-2862.rs [deleted file]
tests/run-pass/issue-825.rs [deleted file]
tests/run-pass/issues_loop_mut_cond.rs [deleted file]
tests/run-pass/match_same_arms_const.rs [deleted file]
tests/run-pass/mut_mut_macro.rs [deleted file]
tests/run-pass/needless_borrow_fp.rs [deleted file]
tests/run-pass/needless_lifetimes_impl_trait.rs [deleted file]
tests/run-pass/procedural_macro.rs [deleted file]
tests/run-pass/regressions.rs [deleted file]
tests/run-pass/returns.rs [deleted file]
tests/run-pass/single-match-else.rs [deleted file]
tests/run-pass/used_underscore_binding_macro.rs [deleted file]
tests/run-pass/whitelist/clippy.toml [deleted file]
tests/run-pass/whitelist/conf_whitelisted.rs [deleted file]
tests/trim_multiline.rs [deleted file]
tests/ui-toml/bad_toml/conf_bad_toml.rs
tests/ui-toml/bad_toml_type/conf_bad_type.rs
tests/ui-toml/conf_deprecated_key/clippy.toml [new file with mode: 0644]
tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs [new file with mode: 0644]
tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr [new file with mode: 0644]
tests/ui-toml/functions_maxlines/clippy.toml [new file with mode: 0644]
tests/ui-toml/functions_maxlines/test.rs [new file with mode: 0644]
tests/ui-toml/functions_maxlines/test.stderr [new file with mode: 0644]
tests/ui-toml/good_toml_no_false_negatives/clippy.toml [new file with mode: 0644]
tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs [new file with mode: 0644]
tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs
tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr
tests/ui-toml/toml_trivially_copy/test.rs
tests/ui-toml/toml_trivially_copy/test.stderr
tests/ui-toml/toml_unknown_key/conf_unknown_key.rs
tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
tests/ui-toml/update-all-references.sh
tests/ui-toml/update-references.sh
tests/ui/absurd-extreme-comparisons.rs
tests/ui/absurd-extreme-comparisons.stderr
tests/ui/approx_const.rs
tests/ui/approx_const.stderr
tests/ui/arithmetic.rs
tests/ui/arithmetic.stderr
tests/ui/assertions_on_constants.rs [new file with mode: 0644]
tests/ui/assertions_on_constants.stderr [new file with mode: 0644]
tests/ui/assign_ops.rs
tests/ui/assign_ops.stderr
tests/ui/assign_ops2.rs
tests/ui/assign_ops2.stderr
tests/ui/attrs.rs
tests/ui/attrs.stderr
tests/ui/author.rs
tests/ui/author.stdout
tests/ui/author/call.rs [changed mode: 0755->0644]
tests/ui/author/call.stdout
tests/ui/author/for_loop.rs
tests/ui/author/for_loop.stderr [new file with mode: 0644]
tests/ui/author/for_loop.stdout
tests/ui/author/if.rs [new file with mode: 0644]
tests/ui/author/if.stderr [new file with mode: 0644]
tests/ui/author/if.stdout [new file with mode: 0644]
tests/ui/author/matches.stderr
tests/ui/author/matches.stout
tests/ui/auxiliary/macro_rules.rs [new file with mode: 0644]
tests/ui/auxiliary/option_helpers.rs [new file with mode: 0644]
tests/ui/auxiliary/proc_macro_derive.rs [new file with mode: 0644]
tests/ui/bit_masks.rs
tests/ui/bit_masks.stderr
tests/ui/blacklisted_name.rs
tests/ui/blacklisted_name.stderr
tests/ui/block_in_if_condition.rs
tests/ui/block_in_if_condition.stderr
tests/ui/bool_comparison.fixed [new file with mode: 0644]
tests/ui/bool_comparison.rs
tests/ui/bool_comparison.stderr
tests/ui/booleans.rs
tests/ui/booleans.stderr
tests/ui/borrow_box.rs
tests/ui/borrow_box.stderr
tests/ui/box_vec.rs
tests/ui/box_vec.stderr
tests/ui/builtin-type-shadow.rs
tests/ui/builtin-type-shadow.stderr
tests/ui/bytecount.rs
tests/ui/bytecount.stderr
tests/ui/cast.rs
tests/ui/cast.stderr
tests/ui/cast_alignment.rs
tests/ui/cast_alignment.stderr
tests/ui/cast_lossless_float.fixed [new file with mode: 0644]
tests/ui/cast_lossless_float.rs
tests/ui/cast_lossless_float.stderr
tests/ui/cast_lossless_integer.fixed [new file with mode: 0644]
tests/ui/cast_lossless_integer.rs
tests/ui/cast_lossless_integer.stderr
tests/ui/cast_ref_to_mut.rs [new file with mode: 0644]
tests/ui/cast_ref_to_mut.stderr [new file with mode: 0644]
tests/ui/cast_size.rs
tests/ui/cast_size.stderr
tests/ui/cfg_attr_rustfmt.fixed [new file with mode: 0644]
tests/ui/cfg_attr_rustfmt.rs [new file with mode: 0644]
tests/ui/cfg_attr_rustfmt.stderr [new file with mode: 0644]
tests/ui/char_lit_as_u8.rs
tests/ui/char_lit_as_u8.stderr
tests/ui/checked_unwrap.rs
tests/ui/checked_unwrap.stderr
tests/ui/clone_on_copy_impl.rs
tests/ui/clone_on_copy_mut.rs
tests/ui/cmp_nan.rs
tests/ui/cmp_nan.stderr
tests/ui/cmp_null.rs
tests/ui/cmp_null.stderr
tests/ui/cmp_owned.rs
tests/ui/cmp_owned.stderr
tests/ui/cognitive_complexity.rs [new file with mode: 0644]
tests/ui/cognitive_complexity.stderr [new file with mode: 0644]
tests/ui/cognitive_complexity_attr_used.rs [new file with mode: 0644]
tests/ui/cognitive_complexity_attr_used.stderr [new file with mode: 0644]
tests/ui/collapsible_if.fixed [new file with mode: 0644]
tests/ui/collapsible_if.rs
tests/ui/collapsible_if.stderr
tests/ui/complex_types.rs
tests/ui/complex_types.stderr
tests/ui/const_static_lifetime.stderr
tests/ui/copies.rs [deleted file]
tests/ui/copies.stderr [deleted file]
tests/ui/copy_iterator.rs [new file with mode: 0644]
tests/ui/copy_iterator.stderr [new file with mode: 0644]
tests/ui/crashes/associated-constant-ice.rs [new file with mode: 0644]
tests/ui/crashes/auxiliary/proc_macro_crash.rs [new file with mode: 0644]
tests/ui/crashes/cc_seme.rs [new file with mode: 0644]
tests/ui/crashes/enum-glob-import-crate.rs [new file with mode: 0644]
tests/ui/crashes/ice-1588.rs [new file with mode: 0644]
tests/ui/crashes/ice-1782.rs [new file with mode: 0644]
tests/ui/crashes/ice-1969.rs [new file with mode: 0644]
tests/ui/crashes/ice-2499.rs [new file with mode: 0644]
tests/ui/crashes/ice-2594.rs [new file with mode: 0644]
tests/ui/crashes/ice-2727.rs [new file with mode: 0644]
tests/ui/crashes/ice-2760.rs [new file with mode: 0644]
tests/ui/crashes/ice-2774.rs [new file with mode: 0644]
tests/ui/crashes/ice-2865.rs [new file with mode: 0644]
tests/ui/crashes/ice-3151.rs [new file with mode: 0644]
tests/ui/crashes/ice-3462.rs [new file with mode: 0644]
tests/ui/crashes/ice-3741.rs [new file with mode: 0644]
tests/ui/crashes/ice-3747.rs [new file with mode: 0644]
tests/ui/crashes/ice-3891.rs [new file with mode: 0644]
tests/ui/crashes/ice-3891.stderr [new file with mode: 0644]
tests/ui/crashes/ice-700.rs [new file with mode: 0644]
tests/ui/crashes/ice_exacte_size.rs [new file with mode: 0644]
tests/ui/crashes/if_same_then_else.rs [new file with mode: 0644]
tests/ui/crashes/issue-2862.rs [new file with mode: 0644]
tests/ui/crashes/issue-825.rs [new file with mode: 0644]
tests/ui/crashes/issues_loop_mut_cond.rs [new file with mode: 0644]
tests/ui/crashes/match_same_arms_const.rs [new file with mode: 0644]
tests/ui/crashes/mut_mut_macro.rs [new file with mode: 0644]
tests/ui/crashes/needless_borrow_fp.rs [new file with mode: 0644]
tests/ui/crashes/needless_lifetimes_impl_trait.rs [new file with mode: 0644]
tests/ui/crashes/procedural_macro.rs [new file with mode: 0644]
tests/ui/crashes/regressions.rs [new file with mode: 0644]
tests/ui/crashes/returns.rs [new file with mode: 0644]
tests/ui/crashes/single-match-else.rs [new file with mode: 0644]
tests/ui/crashes/used_underscore_binding_macro.rs [new file with mode: 0644]
tests/ui/crashes/whitelist/clippy.toml [new file with mode: 0644]
tests/ui/crashes/whitelist/conf_whitelisted.rs [new file with mode: 0644]
tests/ui/cstring.rs
tests/ui/cstring.stderr
tests/ui/cyclomatic_complexity.rs [deleted file]
tests/ui/cyclomatic_complexity.stderr [deleted file]
tests/ui/cyclomatic_complexity_attr_used.rs [deleted file]
tests/ui/cyclomatic_complexity_attr_used.stderr [deleted file]
tests/ui/dbg_macro.rs [new file with mode: 0644]
tests/ui/dbg_macro.stderr [new file with mode: 0644]
tests/ui/decimal_literal_representation.rs
tests/ui/decimal_literal_representation.stderr
tests/ui/default_trait_access.rs
tests/ui/default_trait_access.stderr
tests/ui/deprecated.rs
tests/ui/deprecated.stderr
tests/ui/deref_addrof.fixed [new file with mode: 0644]
tests/ui/deref_addrof.rs [new file with mode: 0644]
tests/ui/deref_addrof.stderr [new file with mode: 0644]
tests/ui/deref_addrof_double_trigger.rs [new file with mode: 0644]
tests/ui/deref_addrof_double_trigger.stderr [new file with mode: 0644]
tests/ui/derive.rs
tests/ui/derive.stderr
tests/ui/diverging_sub_expression.rs
tests/ui/diverging_sub_expression.stderr
tests/ui/dlist.rs
tests/ui/dlist.stderr
tests/ui/doc.rs
tests/ui/doc.stderr
tests/ui/double_comparison.fixed [new file with mode: 0644]
tests/ui/double_comparison.rs
tests/ui/double_comparison.stderr
tests/ui/double_neg.rs
tests/ui/double_neg.stderr
tests/ui/double_parens.rs
tests/ui/double_parens.stderr
tests/ui/drop_bounds.rs [new file with mode: 0644]
tests/ui/drop_bounds.stderr [new file with mode: 0644]
tests/ui/drop_forget_copy.rs
tests/ui/drop_forget_copy.stderr
tests/ui/drop_forget_ref.rs
tests/ui/drop_forget_ref.stderr
tests/ui/duplicate_underscore_argument.rs
tests/ui/duplicate_underscore_argument.stderr
tests/ui/duration_subsec.fixed [new file with mode: 0644]
tests/ui/duration_subsec.rs
tests/ui/duration_subsec.stderr
tests/ui/else_if_without_else.rs
tests/ui/else_if_without_else.stderr
tests/ui/empty_enum.rs
tests/ui/empty_enum.stderr
tests/ui/empty_line_after_outer_attribute.rs
tests/ui/empty_line_after_outer_attribute.stderr
tests/ui/empty_loop.rs [new file with mode: 0644]
tests/ui/empty_loop.stderr [new file with mode: 0644]
tests/ui/entry.rs
tests/ui/entry.stderr
tests/ui/enum_glob_use.rs
tests/ui/enum_glob_use.stderr
tests/ui/enum_variants.rs
tests/ui/enum_variants.stderr
tests/ui/enums_clike.rs
tests/ui/enums_clike.stderr
tests/ui/eq_op.rs
tests/ui/eq_op.stderr
tests/ui/erasing_op.rs
tests/ui/erasing_op.stderr
tests/ui/escape_analysis.rs
tests/ui/escape_analysis.stderr
tests/ui/eta.fixed [new file with mode: 0644]
tests/ui/eta.rs
tests/ui/eta.stderr
tests/ui/eval_order_dependence.rs
tests/ui/eval_order_dependence.stderr
tests/ui/excessive_precision.fixed [new file with mode: 0644]
tests/ui/excessive_precision.rs
tests/ui/excessive_precision.stderr
tests/ui/expect_fun_call.fixed [new file with mode: 0644]
tests/ui/expect_fun_call.rs [new file with mode: 0644]
tests/ui/expect_fun_call.stderr [new file with mode: 0644]
tests/ui/explicit_counter_loop.rs [new file with mode: 0644]
tests/ui/explicit_counter_loop.stderr [new file with mode: 0644]
tests/ui/explicit_write.fixed [new file with mode: 0644]
tests/ui/explicit_write.rs
tests/ui/explicit_write.stderr
tests/ui/fallible_impl_from.rs
tests/ui/fallible_impl_from.stderr
tests/ui/filter_map_next.rs [new file with mode: 0644]
tests/ui/filter_map_next.stderr [new file with mode: 0644]
tests/ui/filter_methods.rs
tests/ui/filter_methods.stderr
tests/ui/find_map.rs [new file with mode: 0644]
tests/ui/find_map.stderr [new file with mode: 0644]
tests/ui/float_cmp.rs
tests/ui/float_cmp.stderr
tests/ui/float_cmp_const.rs
tests/ui/float_cmp_const.stderr
tests/ui/fn_to_numeric_cast.rs [new file with mode: 0644]
tests/ui/fn_to_numeric_cast.stderr [new file with mode: 0644]
tests/ui/for_kv_map.rs [new file with mode: 0644]
tests/ui/for_kv_map.stderr [new file with mode: 0644]
tests/ui/for_loop.rs
tests/ui/for_loop.stderr
tests/ui/for_loop.stdout [new file with mode: 0644]
tests/ui/for_loop_over_option_result.rs [new file with mode: 0644]
tests/ui/for_loop_over_option_result.stderr [new file with mode: 0644]
tests/ui/format.fixed [new file with mode: 0644]
tests/ui/format.rs
tests/ui/format.stderr
tests/ui/formatting.rs
tests/ui/formatting.stderr
tests/ui/functions.rs
tests/ui/functions.stderr
tests/ui/functions_maxlines.rs [new file with mode: 0644]
tests/ui/functions_maxlines.stderr [new file with mode: 0644]
tests/ui/get_unwrap.fixed [new file with mode: 0644]
tests/ui/get_unwrap.rs
tests/ui/get_unwrap.stderr
tests/ui/ice-2636.rs [new file with mode: 0644]
tests/ui/ice-2636.stderr [new file with mode: 0644]
tests/ui/ice-360.rs [new file with mode: 0644]
tests/ui/ice-360.stderr [new file with mode: 0644]
tests/ui/ice-3717.rs [new file with mode: 0644]
tests/ui/ice-3717.stderr [new file with mode: 0644]
tests/ui/identity_conversion.rs
tests/ui/identity_conversion.stderr
tests/ui/identity_op.rs
tests/ui/identity_op.stderr
tests/ui/if_let_redundant_pattern_matching.rs [deleted file]
tests/ui/if_let_redundant_pattern_matching.stderr [deleted file]
tests/ui/if_not_else.rs
tests/ui/if_not_else.stderr
tests/ui/if_same_then_else.rs [new file with mode: 0644]
tests/ui/if_same_then_else.stderr [new file with mode: 0644]
tests/ui/ifs_same_cond.rs [new file with mode: 0644]
tests/ui/ifs_same_cond.stderr [new file with mode: 0644]
tests/ui/impl.rs
tests/ui/impl.stderr
tests/ui/implicit_hasher.rs
tests/ui/implicit_hasher.stderr
tests/ui/implicit_return.rs [new file with mode: 0644]
tests/ui/implicit_return.stderr [new file with mode: 0644]
tests/ui/inconsistent_digit_grouping.fixed [new file with mode: 0644]
tests/ui/inconsistent_digit_grouping.rs
tests/ui/inconsistent_digit_grouping.stderr
tests/ui/indexing_slicing.rs
tests/ui/indexing_slicing.stderr
tests/ui/infallible_destructuring_match.fixed [new file with mode: 0644]
tests/ui/infallible_destructuring_match.rs
tests/ui/infallible_destructuring_match.stderr
tests/ui/infinite_iter.rs
tests/ui/infinite_iter.stderr
tests/ui/infinite_loop.rs
tests/ui/infinite_loop.stderr
tests/ui/inline_fn_without_body.rs
tests/ui/inline_fn_without_body.stderr
tests/ui/int_plus_one.rs
tests/ui/int_plus_one.stderr
tests/ui/into_iter_on_ref.fixed [new file with mode: 0644]
tests/ui/into_iter_on_ref.rs [new file with mode: 0644]
tests/ui/into_iter_on_ref.stderr [new file with mode: 0644]
tests/ui/invalid_ref.rs
tests/ui/invalid_ref.stderr
tests/ui/invalid_upcast_comparisons.rs
tests/ui/invalid_upcast_comparisons.stderr
tests/ui/issue-3145.rs [new file with mode: 0644]
tests/ui/issue-3145.stderr [new file with mode: 0644]
tests/ui/issue_2356.rs
tests/ui/issue_2356.stderr
tests/ui/issue_3849.rs [new file with mode: 0644]
tests/ui/issue_3849.stdout [new file with mode: 0644]
tests/ui/item_after_statement.rs
tests/ui/item_after_statement.stderr
tests/ui/iter_nth.rs [new file with mode: 0644]
tests/ui/iter_nth.stderr [new file with mode: 0644]
tests/ui/iter_skip_next.rs [new file with mode: 0644]
tests/ui/iter_skip_next.stderr [new file with mode: 0644]
tests/ui/large_digit_groups.fixed [new file with mode: 0644]
tests/ui/large_digit_groups.rs
tests/ui/large_digit_groups.stderr
tests/ui/large_enum_variant.rs
tests/ui/large_enum_variant.stderr
tests/ui/len_without_is_empty.rs [new file with mode: 0644]
tests/ui/len_without_is_empty.stderr [new file with mode: 0644]
tests/ui/len_zero.fixed [new file with mode: 0644]
tests/ui/len_zero.rs
tests/ui/len_zero.stderr
tests/ui/let_if_seq.rs
tests/ui/let_if_seq.stderr
tests/ui/let_return.rs
tests/ui/let_return.stderr
tests/ui/let_unit.rs
tests/ui/let_unit.stderr
tests/ui/lifetimes.rs
tests/ui/lifetimes.stderr
tests/ui/lint_without_lint_pass.rs [new file with mode: 0644]
tests/ui/lint_without_lint_pass.stderr [new file with mode: 0644]
tests/ui/literals.rs
tests/ui/literals.stderr
tests/ui/manual_memcpy.rs [new file with mode: 0644]
tests/ui/manual_memcpy.stderr [new file with mode: 0644]
tests/ui/many_single_char_names.rs [new file with mode: 0644]
tests/ui/many_single_char_names.stderr [new file with mode: 0644]
tests/ui/map_clone.fixed [new file with mode: 0644]
tests/ui/map_clone.rs
tests/ui/map_clone.stderr
tests/ui/map_flatten.rs [new file with mode: 0644]
tests/ui/map_flatten.stderr [new file with mode: 0644]
tests/ui/map_unit_fn.rs [new file with mode: 0644]
tests/ui/map_unit_fn.stderr [deleted file]
tests/ui/match_as_ref.fixed [new file with mode: 0644]
tests/ui/match_as_ref.rs [new file with mode: 0644]
tests/ui/match_as_ref.stderr [new file with mode: 0644]
tests/ui/match_bool.rs
tests/ui/match_bool.stderr
tests/ui/match_overlapping_arm.rs [new file with mode: 0644]
tests/ui/match_overlapping_arm.stderr [new file with mode: 0644]
tests/ui/match_same_arms.rs [new file with mode: 0644]
tests/ui/match_same_arms.stderr [new file with mode: 0644]
tests/ui/matches.rs
tests/ui/matches.stderr
tests/ui/mem_discriminant.rs [new file with mode: 0644]
tests/ui/mem_discriminant.stderr [new file with mode: 0644]
tests/ui/mem_forget.rs
tests/ui/mem_forget.stderr
tests/ui/mem_replace.fixed [new file with mode: 0644]
tests/ui/mem_replace.rs [new file with mode: 0644]
tests/ui/mem_replace.stderr [new file with mode: 0644]
tests/ui/methods.rs
tests/ui/methods.stderr
tests/ui/min_max.rs
tests/ui/min_max.stderr
tests/ui/missing-doc-crate-missing.rs [new file with mode: 0644]
tests/ui/missing-doc-crate-missing.stderr [new file with mode: 0644]
tests/ui/missing-doc-crate.rs [new file with mode: 0644]
tests/ui/missing-doc-crate.stderr [new file with mode: 0644]
tests/ui/missing-doc.rs
tests/ui/missing-doc.stderr
tests/ui/missing_const_for_fn/cant_be_const.rs [new file with mode: 0644]
tests/ui/missing_const_for_fn/cant_be_const.stderr [new file with mode: 0644]
tests/ui/missing_const_for_fn/could_be_const.rs [new file with mode: 0644]
tests/ui/missing_const_for_fn/could_be_const.stderr [new file with mode: 0644]
tests/ui/missing_inline.rs
tests/ui/missing_inline.stderr
tests/ui/mistyped_literal_suffix.fixed [new file with mode: 0644]
tests/ui/mistyped_literal_suffix.rs [new file with mode: 0644]
tests/ui/mistyped_literal_suffix.stderr [new file with mode: 0644]
tests/ui/module_inception.rs
tests/ui/module_inception.stderr
tests/ui/module_name_repetitions.rs [new file with mode: 0644]
tests/ui/module_name_repetitions.stderr [new file with mode: 0644]
tests/ui/modulo_one.rs
tests/ui/modulo_one.stderr
tests/ui/mut_from_ref.rs
tests/ui/mut_from_ref.stderr
tests/ui/mut_mut.rs
tests/ui/mut_mut.stderr
tests/ui/mut_range_bound.rs
tests/ui/mut_range_bound.stderr
tests/ui/mut_reference.rs
tests/ui/mut_reference.stderr
tests/ui/mutex_atomic.rs
tests/ui/mutex_atomic.stderr
tests/ui/my_lint.rs [new file with mode: 0644]
tests/ui/needless_bool.rs
tests/ui/needless_bool.stderr
tests/ui/needless_borrow.rs
tests/ui/needless_borrow.stderr
tests/ui/needless_borrowed_ref.rs
tests/ui/needless_borrowed_ref.stderr
tests/ui/needless_collect.rs [new file with mode: 0644]
tests/ui/needless_collect.stderr [new file with mode: 0644]
tests/ui/needless_continue.rs
tests/ui/needless_continue.stderr
tests/ui/needless_pass_by_value.rs
tests/ui/needless_pass_by_value.stderr
tests/ui/needless_pass_by_value_proc_macro.rs
tests/ui/needless_range_loop.rs
tests/ui/needless_range_loop.stderr
tests/ui/needless_return.rs
tests/ui/needless_return.stderr
tests/ui/needless_update.rs
tests/ui/needless_update.stderr
tests/ui/neg_cmp_op_on_partial_ord.rs
tests/ui/neg_cmp_op_on_partial_ord.stderr
tests/ui/neg_multiply.rs
tests/ui/neg_multiply.stderr
tests/ui/never_loop.rs
tests/ui/never_loop.stderr
tests/ui/new_ret_no_self.rs [new file with mode: 0644]
tests/ui/new_ret_no_self.stderr [new file with mode: 0644]
tests/ui/new_without_default.rs
tests/ui/new_without_default.stderr
tests/ui/no_effect.rs
tests/ui/no_effect.stderr
tests/ui/non_copy_const.rs
tests/ui/non_copy_const.stderr
tests/ui/non_expressive_names.rs
tests/ui/non_expressive_names.stderr
tests/ui/non_expressive_names.stdout [new file with mode: 0644]
tests/ui/ok_expect.rs
tests/ui/ok_expect.stderr
tests/ui/ok_if_let.rs
tests/ui/ok_if_let.stderr
tests/ui/op_ref.rs
tests/ui/op_ref.stderr
tests/ui/open_options.rs
tests/ui/open_options.stderr
tests/ui/option_map_or_none.fixed [new file with mode: 0644]
tests/ui/option_map_or_none.rs [new file with mode: 0644]
tests/ui/option_map_or_none.stderr [new file with mode: 0644]
tests/ui/option_map_unit_fn.rs
tests/ui/option_map_unit_fn.stderr
tests/ui/option_option.rs
tests/ui/option_option.stderr
tests/ui/or_fun_call.rs [new file with mode: 0644]
tests/ui/or_fun_call.stderr [new file with mode: 0644]
tests/ui/overflow_check_conditional.rs
tests/ui/overflow_check_conditional.stderr
tests/ui/panic_unimplemented.rs
tests/ui/panic_unimplemented.stderr
tests/ui/partialeq_ne_impl.rs
tests/ui/partialeq_ne_impl.stderr
tests/ui/path_buf_push_overwrite.fixed [new file with mode: 0644]
tests/ui/path_buf_push_overwrite.rs [new file with mode: 0644]
tests/ui/path_buf_push_overwrite.stderr [new file with mode: 0644]
tests/ui/patterns.rs
tests/ui/patterns.stderr
tests/ui/precedence.fixed [new file with mode: 0644]
tests/ui/precedence.rs
tests/ui/precedence.stderr
tests/ui/print.rs
tests/ui/print.stderr
tests/ui/print_literal.rs
tests/ui/print_literal.stderr
tests/ui/print_with_newline.rs
tests/ui/print_with_newline.stderr
tests/ui/println_empty_string.fixed [new file with mode: 0644]
tests/ui/println_empty_string.rs
tests/ui/println_empty_string.stderr
tests/ui/proc_macro.rs [new file with mode: 0755]
tests/ui/proc_macro.stderr [new file with mode: 0644]
tests/ui/ptr_arg.rs
tests/ui/ptr_arg.stderr
tests/ui/ptr_offset_with_cast.fixed [new file with mode: 0644]
tests/ui/ptr_offset_with_cast.rs [new file with mode: 0644]
tests/ui/ptr_offset_with_cast.stderr [new file with mode: 0644]
tests/ui/question_mark.rs
tests/ui/question_mark.stderr
tests/ui/range.rs
tests/ui/range.stderr
tests/ui/range_plus_minus_one.rs
tests/ui/range_plus_minus_one.stderr
tests/ui/redundant_clone.rs [new file with mode: 0644]
tests/ui/redundant_clone.stderr [new file with mode: 0644]
tests/ui/redundant_closure_call.rs
tests/ui/redundant_closure_call.stderr
tests/ui/redundant_field_names.fixed [new file with mode: 0644]
tests/ui/redundant_field_names.rs
tests/ui/redundant_field_names.stderr
tests/ui/redundant_pattern_matching.rs [new file with mode: 0644]
tests/ui/redundant_pattern_matching.stderr [new file with mode: 0644]
tests/ui/reference.rs [deleted file]
tests/ui/reference.stderr [deleted file]
tests/ui/regex.rs
tests/ui/regex.stderr
tests/ui/rename.rs [new file with mode: 0644]
tests/ui/rename.stderr [new file with mode: 0644]
tests/ui/renamed_builtin_attr.rs [new file with mode: 0644]
tests/ui/renamed_builtin_attr.stderr [new file with mode: 0644]
tests/ui/replace_consts.fixed [new file with mode: 0644]
tests/ui/replace_consts.rs
tests/ui/replace_consts.stderr
tests/ui/result_map_unit_fn.rs
tests/ui/result_map_unit_fn.stderr
tests/ui/result_map_unwrap_or_else.rs [new file with mode: 0644]
tests/ui/result_map_unwrap_or_else.stderr [new file with mode: 0644]
tests/ui/serde.rs
tests/ui/serde.stderr
tests/ui/shadow.rs
tests/ui/shadow.stderr
tests/ui/short_circuit_statement.rs
tests/ui/short_circuit_statement.stderr
tests/ui/similar_names.rs [new file with mode: 0644]
tests/ui/similar_names.stderr [new file with mode: 0644]
tests/ui/single_char_pattern.fixed [new file with mode: 0644]
tests/ui/single_char_pattern.rs
tests/ui/single_char_pattern.stderr
tests/ui/single_match.rs
tests/ui/single_match.stderr
tests/ui/single_match_else.rs [new file with mode: 0644]
tests/ui/single_match_else.stderr [new file with mode: 0644]
tests/ui/slow_vector_initialization.rs [new file with mode: 0644]
tests/ui/slow_vector_initialization.stderr [new file with mode: 0644]
tests/ui/slow_vector_initialization.stdout [new file with mode: 0644]
tests/ui/starts_ends_with.fixed [new file with mode: 0644]
tests/ui/starts_ends_with.rs
tests/ui/starts_ends_with.stderr
tests/ui/string_extend.fixed [new file with mode: 0644]
tests/ui/string_extend.rs
tests/ui/string_extend.stderr
tests/ui/string_lit_as_bytes.fixed [new file with mode: 0644]
tests/ui/string_lit_as_bytes.rs [new file with mode: 0644]
tests/ui/string_lit_as_bytes.stderr [new file with mode: 0644]
tests/ui/strings.rs
tests/ui/strings.stderr
tests/ui/stutter.rs [deleted file]
tests/ui/stutter.stderr [deleted file]
tests/ui/suspicious_arithmetic_impl.rs
tests/ui/suspicious_arithmetic_impl.stderr
tests/ui/swap.rs
tests/ui/swap.stderr
tests/ui/temporary_assignment.rs
tests/ui/temporary_assignment.stderr
tests/ui/toplevel_ref_arg.rs
tests/ui/toplevel_ref_arg.stderr
tests/ui/trailing_zeros.rs
tests/ui/trailing_zeros.stderr
tests/ui/transmute.rs
tests/ui/transmute.stderr
tests/ui/transmute_32bit.rs
tests/ui/transmute_64bit.rs
tests/ui/transmute_64bit.stderr
tests/ui/transmuting_null.rs [new file with mode: 0644]
tests/ui/transmuting_null.stderr [new file with mode: 0644]
tests/ui/trivially_copy_pass_by_ref.rs
tests/ui/trivially_copy_pass_by_ref.stderr
tests/ui/ty_fn_sig.stderr [new file with mode: 0644]
tests/ui/types.fixed [new file with mode: 0644]
tests/ui/types.rs
tests/ui/types.stderr
tests/ui/types_fn_to_int.rs [deleted file]
tests/ui/types_fn_to_int.stderr [deleted file]
tests/ui/unicode.rs
tests/ui/unicode.stderr
tests/ui/unit_arg.fixed [new file with mode: 0644]
tests/ui/unit_arg.rs
tests/ui/unit_arg.stderr
tests/ui/unit_cmp.rs
tests/ui/unit_cmp.stderr
tests/ui/unknown_attribute.rs [new file with mode: 0644]
tests/ui/unknown_attribute.stderr [new file with mode: 0644]
tests/ui/unknown_clippy_lints.rs [new file with mode: 0644]
tests/ui/unknown_clippy_lints.stderr [new file with mode: 0644]
tests/ui/unnecessary_clone.rs
tests/ui/unnecessary_clone.stderr
tests/ui/unnecessary_filter_map.rs [new file with mode: 0644]
tests/ui/unnecessary_filter_map.stderr [new file with mode: 0644]
tests/ui/unnecessary_fold.fixed [new file with mode: 0644]
tests/ui/unnecessary_fold.rs
tests/ui/unnecessary_fold.stderr
tests/ui/unnecessary_operation.rs [new file with mode: 0644]
tests/ui/unnecessary_operation.stderr [new file with mode: 0644]
tests/ui/unnecessary_ref.fixed [new file with mode: 0644]
tests/ui/unnecessary_ref.rs
tests/ui/unnecessary_ref.stderr
tests/ui/unneeded_field_pattern.rs
tests/ui/unneeded_field_pattern.stderr
tests/ui/unreadable_literal.fixed [new file with mode: 0644]
tests/ui/unreadable_literal.rs
tests/ui/unreadable_literal.stderr
tests/ui/unsafe_removed_from_name.rs
tests/ui/unsafe_removed_from_name.stderr
tests/ui/unused_io_amount.rs
tests/ui/unused_io_amount.stderr
tests/ui/unused_labels.rs
tests/ui/unused_labels.stderr
tests/ui/unused_lt.rs
tests/ui/unused_lt.stderr
tests/ui/unused_unit.fixed [new file with mode: 0644]
tests/ui/unused_unit.rs [new file with mode: 0644]
tests/ui/unused_unit.stderr [new file with mode: 0644]
tests/ui/unwrap_or.rs
tests/ui/unwrap_or.stderr
tests/ui/update-all-references.sh
tests/ui/update-references.sh
tests/ui/use_self.fixed [new file with mode: 0644]
tests/ui/use_self.rs
tests/ui/use_self.stderr
tests/ui/used_underscore_binding.rs
tests/ui/used_underscore_binding.stderr
tests/ui/useful_asref.rs [new file with mode: 0644]
tests/ui/useless_asref.fixed [new file with mode: 0644]
tests/ui/useless_asref.rs
tests/ui/useless_asref.stderr
tests/ui/useless_attribute.rs
tests/ui/useless_attribute.stderr
tests/ui/vec.fixed [new file with mode: 0644]
tests/ui/vec.rs
tests/ui/vec.stderr
tests/ui/vec_box_sized.fixed [new file with mode: 0644]
tests/ui/vec_box_sized.rs [new file with mode: 0644]
tests/ui/vec_box_sized.stderr [new file with mode: 0644]
tests/ui/while_let_loop.rs [new file with mode: 0644]
tests/ui/while_let_loop.stderr [new file with mode: 0644]
tests/ui/while_let_on_iterator.rs [new file with mode: 0644]
tests/ui/while_let_on_iterator.stderr [new file with mode: 0644]
tests/ui/while_loop.rs [deleted file]
tests/ui/while_loop.stderr [deleted file]
tests/ui/wildcard_enum_match_arm.rs [new file with mode: 0644]
tests/ui/wildcard_enum_match_arm.stderr [new file with mode: 0644]
tests/ui/write_literal.rs
tests/ui/write_literal.stderr
tests/ui/write_with_newline.rs
tests/ui/write_with_newline.stderr
tests/ui/writeln_empty_string.fixed [new file with mode: 0644]
tests/ui/writeln_empty_string.rs
tests/ui/writeln_empty_string.stderr
tests/ui/wrong_self_convention.rs
tests/ui/wrong_self_convention.stderr
tests/ui/zero_div_zero.rs
tests/ui/zero_div_zero.stderr
tests/ui/zero_ptr.rs
tests/ui/zero_ptr.stderr
tests/versioncheck.rs
tests/without_block_comments.rs [deleted file]
util/dev [new file with mode: 0755]
util/dogfood.sh [deleted file]
util/export.py
util/fetch_prs_between.sh [new file with mode: 0755]
util/gh-pages/index.html
util/gh-pages/versions.html
util/lintlib.py
util/update_lints.py

diff --git a/.cargo/config b/.cargo/config
new file mode 100644 (file)
index 0000000..b4bc441
--- /dev/null
@@ -0,0 +1,5 @@
+[alias]
+uitest = "test --test compile-test"
+
+[build]
+rustflags = ["-Zunstable-options"]
diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..796afdb
--- /dev/null
@@ -0,0 +1,5 @@
+[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
+
+* text=auto eol=lf
+*.rs rust
+*.fixed linguist-language=Rust
index a19cb5d2c7cfdfd6ab0292597875c364d3e7b738..15006a07b44f2b1831ea8a685c47aeb75634729f 100644 (file)
@@ -1,7 +1,7 @@
 <!--
 Hi there! Whether you've come to make a suggestion for a new lint, an improvement to an existing lint or to report a bug or a false positive in Clippy, you've come to the right place.
 
-If you want to report that Clippy does not compile, please be sure to be using the *latest version* of *Rust nightly*! Compiler plugins are highly unstable and will only work with a nightly Rust for now. If you are but still have a problem, please let us now!
+For bug reports and false positives, please include the output of `cargo clippy -V` in the report.
 
 Thank you for using Clippy!
 
diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
new file mode 100644 (file)
index 0000000..5567b84
--- /dev/null
@@ -0,0 +1,28 @@
+<!--
+Thank you for making Clippy better!
+
+We're collecting our changelog from pull request descriptions.
+If your PR only updates to the latest nightly, you can leave the
+`changelog` entry as `none`. Otherwise, please write a short comment
+explaining your change.
+
+If your PR fixes an issue, you can add "fixes #issue_number" into this
+PR description. This way the issue will be automatically closed when
+your PR is merged.
+
+If you added a new lint, here's a checklist for things that will be
+checked during review or continuous integration.
+
+- [ ] Followed [lint naming conventions][lint_naming]
+- [ ] Added passing UI tests (including committed `.stderr` file)
+- [ ] `cargo test` passes locally
+- [ ] Executed `util/dev update_lints`
+- [ ] Added lint documentation
+- [ ] Run `cargo fmt`
+
+Note that you can skip the above if you are just opening a WIP PR in
+order to get feedback.
+
+Delete this line and everything above before opening your PR -->
+
+changelog: none
index 1d206e61167e9c33be0dd7f3764887167d053bb6..a242c35c3aecfce31baaa525cf93b7339496dd1f 100755 (executable)
@@ -1,4 +1,5 @@
 #!/bin/bash
+
 # Automatically deploy on gh-pages
 
 set -ex
index 5ca1e06a5e5a9d22a5e0f75dc1c9838aec516a41..f1f4fa4e242aafc008a3a74ab9af21100a0eb35a 100644 (file)
@@ -15,10 +15,12 @@ out
 *.exe
 
 # Generated by Cargo
-Cargo.lock
+*Cargo.lock
 /target
 /clippy_lints/target
 /clippy_workspace_tests/target
+/clippy_dev/target
+/rustc_tools_util/target
 
 # Generated by dogfood
 /target_recur/
@@ -33,6 +35,3 @@ helper.txt
 *.iml
 .vscode
 .idea
-
-# Used by the Clippy build script
-min_version.txt
index c6bd67ae0f3df6ffed8283d7a9f74fa0236f3cbf..4ca18a93ea86e56fe3aeec5f0736bbf37f225587 100644 (file)
@@ -4,57 +4,102 @@ rust: nightly
 
 os:
   - linux
-  # - osx # doesn't even start atm. Not sure what travis is up to. Disabling to reduce the noise
+  - osx
+  - windows
 
-sudo: false
+branches:
+  # Don't build these branches
+  except:
+    # Used by bors
+    - trying.tmp
+    - staging.tmp
 
 env:
  global:
-   # TRAVIS_TOKEN_CLIPPY_SERVICE
-   - secure: dj8SwwuRGuzbo2wZq5z7qXIf7P3p7cbSGs1I3pvXQmB6a58gkLiRn/qBcIIegdt/nzXs+Z0Nug+DdesYVeUPxk1hIa/eeU8p6mpyTtZ+30H4QVgVzd0VCthB5F/NUiPVxTgpGpEgCM9/p72xMwTn7AAJfsGqk7AJ4FS5ZZKhqFI=
    - RUST_BACKTRACE=1
 
-before_install:
- - |
-    # work-around for issue https://github.com/travis-ci/travis-ci/issues/6307
-    # might not be necessary in the future
-    if [ "$TRAVIS_OS_NAME" == "osx" ]; then
-     command curl -sSL https://rvm.io/mpapis.asc | gpg --import -
-     rvm get stable
-    fi
-
 install:
   - |
     if [ -z ${INTEGRATION} ]; then
-      . $HOME/.nvm/nvm.sh
-      nvm install stable
-      nvm use stable
-      npm install remark-cli remark-lint
+      rustup component add rustfmt || cargo install --git https://github.com/rust-lang/rustfmt/ --force
+      if [ "$TRAVIS_OS_NAME" == "linux" ]; then
+        . $HOME/.nvm/nvm.sh
+        nvm install stable
+        nvm use stable
+        npm install remark-cli remark-lint
+      fi
+      if [ "$TRAVIS_OS_NAME" == "windows" ]; then
+        choco install windows-sdk-10.0
+      fi
     fi
 
+# disabling the integration tests in forks should be done with
+# if: fork = false
+# but this is currently buggy travis-ci/travis-ci#9118
 matrix:
+  fast_finish: true
   include:
-    - env: BASE_TESTS=true # runs the base tests
+    # Builds that are executed for every PR
+    - os: osx # run base tests on both platforms
+      env: BASE_TESTS=true
+    - os: linux
+      env: BASE_TESTS=true
+    - os: windows
+      env: CARGO_INCREMENTAL=0 BASE_TESTS=true
+
+    # Builds that are only executed when a PR is r+ed or a try build is started
+    # We don't want to run these always because they go towards
+    # the build limit within the Travis rust-lang account.
+    # The jobs are approximately sorted by execution time
     - env: INTEGRATION=rust-lang/cargo
-    - env: INTEGRATION=rust-lang-nursery/rand
+      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=Geal/nom
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+    - env: INTEGRATION=rust-lang/rustfmt
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+    - env: INTEGRATION=hyperium/hyper
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+    - env: INTEGRATION=bluss/rust-itertools
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+    - env: INTEGRATION=serde-rs/serde
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
     - env: INTEGRATION=rust-lang-nursery/stdsimd
-    - env: INTEGRATION=rust-lang-nursery/rustfmt
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+    - env: INTEGRATION=rust-random/rand
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
     - env: INTEGRATION=rust-lang-nursery/futures-rs
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+    - env: INTEGRATION=Marwes/combine
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
     - env: INTEGRATION=rust-lang-nursery/failure
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
     - env: INTEGRATION=rust-lang-nursery/log
-    - env: INTEGRATION=rust-lang-nursery/chalk
-    - env: INTEGRATION=rust-lang-nursery/rls
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
     - env: INTEGRATION=chronotope/chrono
-    - env: INTEGRATION=serde-rs/serde
-    - env: INTEGRATION=Geal/nom
-    - env: INTEGRATION=hyperium/hyper
+      if: repo =~ /^rust-lang\/rust-clippy$/ AND branch IN (auto, try)
+  allow_failures:
+  - os: windows
+    env: CARGO_INCREMENTAL=0 BASE_TESTS=true
+# prevent these jobs with default env vars
+  exclude:
+    - os: linux
+    - os: osx
+    - os: windows
 
 script:
+  - |
+      rm rust-toolchain
+      ./setup-toolchain.sh
+      export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib
   - |
     if [ -z ${INTEGRATION} ]; then
-      ./ci/base-tests.sh
+      ./ci/base-tests.sh && sleep 5
     else
-      ./ci/integration-tests.sh
+      ./ci/integration-tests.sh && sleep 5
     fi
 
 after_success: |
@@ -66,20 +111,5 @@ after_success: |
     else
       echo "Not deploying, because we're in an integration test run"
     fi
-    # trigger rebuild of the clippy-service, to keep it up to date with clippy itself
-    if [ "$TRAVIS_PULL_REQUEST" == "false" ] &&
-       [ "$TRAVIS_REPO_SLUG" == "Manishearth/rust-clippy" ] &&
-       [ "$TRAVIS_BRANCH" == "master" ] &&
-       [ "$TRAVIS_TOKEN_CLIPPY_SERVICE" != "" ] ; then
-       curl -s -X POST \
-          -H "Content-Type: application/json" \
-          -H "Accept: application/json" \
-          -H "Travis-API-Version: 3" \
-          -H "Authorization: token $TRAVIS_TOKEN_CLIPPY_SERVICE" \
-          -d "{ \"request\": { \"branch\":\"master\" }}" \
-          https://api.travis-ci.org/repo/gnunicorn%2Fclippy-service/requests
-    else
-      echo "Ignored"
-    fi
     set +e
   fi
index 48585df06031c48d04487839b627d1a07c845f33..44787f4f28187700358c446805b2418c4c749f9f 100644 (file)
@@ -1,7 +1,211 @@
 # Change Log
+
 All notable changes to this project will be documented in this file.
 
-## 0.0.212
+## Unreleased / In Rust Beta or Nightly
+
+[eb9f9b1...master](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...master)
+
+## Rust 1.35 (beta)
+[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e)
+
+ * New lint: [`drop_bounds`] to detect `T: Drop` bounds
+ * Rename `cyclomatic_complexity` to [`cognitive_complexity`], start work on making lint more practical for Rust code
+ * Move [`get_unwrap`] to the restriction category
+ * Improve suggestions for [`iter_cloned_collect`]
+ * Improve suggestions for [`cast_lossless`] to suggest suffixed literals
+ * Fix false positives in [`print_with_newline`] and [`write_with_newline`] pertaining to raw strings
+ * Fix false positive in [`needless_range_loop`] pertaining to structs without a `.iter()`
+ * Fix false positive in [`bool_comparison`] pertaining to non-bool types
+ * Fix false positive in [`redundant_closure`] pertaining to differences in borrows
+ * Fix false positive in [`option_map_unwrap_or`] on non-copy types
+ * Fix false positives in [`missing_const_for_fn`] pertaining to macros and trait method impls
+ * Fix false positive in [`needless_pass_by_value`] pertaining to procedural macros
+ * Fix false positive in [`needless_continue`] pertaining to loop labels
+ * Fix false positive for [`boxed_local`] pertaining to arguments moved into closures
+ * Fix false positive for [`use_self`] in nested functions
+ * Fix suggestion for [`expect_fun_call`] (https://github.com/rust-lang/rust-clippy/pull/3846)
+ * Fix suggestion for [`explicit_counter_loop`] to deal with parenthesizing range variables
+ * Fix suggestion for [`single_char_pattern`] to correctly escape single quotes
+ * Avoid triggering [`redundant_closure`] in macros
+ * ICE fixes: [#3805](https://github.com/rust-lang/rust-clippy/pull/3805), [#3772](https://github.com/rust-lang/rust-clippy/pull/3772), [#3741](https://github.com/rust-lang/rust-clippy/pull/3741)
+
+## Rust 1.34 (2019-04-10)
+
+[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380)
+
+* New lint: [`assertions_on_constants`] to detect for example `assert!(true)`
+* New lint: [`dbg_macro`] to detect uses of the `dbg!` macro
+* New lint: [`missing_const_for_fn`] that can suggest functions to be made `const`
+* New lint: [`too_many_lines`] to detect functions with excessive LOC. It can be
+  configured using the `too-many-lines-threshold` configuration.
+* New lint: [`wildcard_enum_match_arm`] to check for wildcard enum matches using `_`
+* Expand `redundant_closure` to also work for methods (not only functions)
+* Fix ICEs in `vec_box`, `needless_pass_by_value` and `implicit_hasher`
+* Fix false positive in `cast_sign_loss`
+* Fix false positive in `integer_arithmetic`
+* Fix false positive in `unit_arg`
+* Fix false positives in `implicit_return`
+* Add suggestion to `explicit_write`
+* Improve suggestions for `question_mark` lint
+* Fix incorrect suggestion for `cast_lossless`
+* Fix incorrect suggestion for `expect_fun_call`
+* Fix incorrect suggestion for `needless_bool`
+* Fix incorrect suggestion for `needless_range_loop`
+* Fix incorrect suggestion for `use_self`
+* Fix incorrect suggestion for `while_let_on_iterator`
+* Clippy is now slightly easier to invoke in non-cargo contexts. See
+  [#3665][pull3665] for more details.
+* We now have [improved documentation][adding_lints] on how to add new lints
+
+## Rust 1.33 (2019-02-26)
+
+[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724)
+
+* New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`]
+* The `rust-clippy` repository is now part of the `rust-lang` org.
+* Rename `stutter` to `module_name_repetitions`
+* Merge `new_without_default_derive` into `new_without_default` lint
+* Move `large_digit_groups` from `style` group to `pedantic`
+* Expand `bool_comparison` to check for `<`, `<=`, `>`, `>=`, and `!=`
+  comparisons against booleans
+* Expand `no_effect` to detect writes to constants such as `A_CONST.field = 2`
+* Expand `redundant_clone` to work on struct fields
+* Expand `suspicious_else_formatting` to detect `if .. {..} {..}`
+* Expand `use_self` to work on tuple structs and also in local macros
+* Fix ICE in `result_map_unit_fn` and `option_map_unit_fn`
+* Fix false positives in `implicit_return`
+* Fix false positives in `use_self`
+* Fix false negative in `clone_on_copy`
+* Fix false positive in `doc_markdown`
+* Fix false positive in `empty_loop`
+* Fix false positive in `if_same_then_else`
+* Fix false positive in `infinite_iter`
+* Fix false positive in `question_mark`
+* Fix false positive in `useless_asref`
+* Fix false positive in `wildcard_dependencies`
+* Fix false positive in `write_with_newline`
+* Add suggestion to `explicit_write`
+* Improve suggestions for `question_mark` lint
+* Fix incorrect suggestion for `get_unwrap`
+
+## Rust 1.32 (2019-01-17)
+
+[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be)
+
+* New lints: [`slow_vector_initialization`], [`mem_discriminant_non_enum`],
+  [`redundant_clone`], [`wildcard_dependencies`],
+  [`into_iter_on_ref`], [`into_iter_on_array`], [`deprecated_cfg_attr`],
+  [`mem_discriminant_non_enum`], [`cargo_common_metadata`]
+* Add support for `u128` and `i128` to integer related lints
+* Add float support to `mistyped_literal_suffixes`
+* Fix false positives in `use_self`
+* Fix false positives in `missing_comma`
+* Fix false positives in `new_ret_no_self`
+* Fix false positives in `possible_missing_comma`
+* Fix false positive in `integer_arithmetic` in constant items
+* Fix false positive in `needless_borrow`
+* Fix false positive in `out_of_bounds_indexing`
+* Fix false positive in `new_without_default_derive`
+* Fix false positive in `string_lit_as_bytes`
+* Fix false negative in `out_of_bounds_indexing`
+* Fix false negative in `use_self`. It will now also check existential types
+* Fix incorrect suggestion for `redundant_closure_call`
+* Fix various suggestions that contained expanded macros
+* Fix `bool_comparison` triggering 3 times on on on the same code
+* Expand `trivially_copy_pass_by_ref` to work on trait methods
+* Improve suggestion for `needless_range_loop`
+* Move `needless_pass_by_value` from `pedantic` group to `style`
+
+## Rust 1.31 (2018-12-06)
+
+[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2)
+
+* Clippy has been relicensed under a dual MIT / Apache license.
+  See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more
+  information.
+* With Rust 1.31, Clippy is no longer available via crates.io. The recommended
+  installation method is via `rustup component add clippy`.
+* New lints: [`redundant_pattern_matching`], [`unnecessary_filter_map`],
+  [`unused_unit`], [`map_flatten`], [`mem_replace_option_with_none`]
+* Fix ICE in `if_let_redundant_pattern_matching`
+* Fix ICE in `needless_pass_by_value` when encountering a generic function
+  argument with a lifetime parameter
+* Fix ICE in `needless_range_loop`
+* Fix ICE in `single_char_pattern` when encountering a constant value
+* Fix false positive in `assign_op_pattern`
+* Fix false positive in `boxed_local` on trait implementations
+* Fix false positive in `cmp_owned`
+* Fix false positive in `collapsible_if` when conditionals have comments
+* Fix false positive in `double_parens`
+* Fix false positive in `excessive_precision`
+* Fix false positive in `explicit_counter_loop`
+* Fix false positive in `fn_to_numeric_cast_with_truncation`
+* Fix false positive in `map_clone`
+* Fix false positive in `new_ret_no_self`
+* Fix false positive in `new_without_default` when `new` is unsafe
+* Fix false positive in `type_complexity` when using extern types
+* Fix false positive in `useless_format`
+* Fix false positive in `wrong_self_convention`
+* Fix incorrect suggestion for `excessive_precision`
+* Fix incorrect suggestion for `expect_fun_call`
+* Fix incorrect suggestion for `get_unwrap`
+* Fix incorrect suggestion for `useless_format`
+* `fn_to_numeric_cast_with_truncation` lint can be disabled again
+* Improve suggestions for `manual_memcpy`
+* Improve help message for `needless_lifetimes`
+
+## Rust 1.30 (2018-10-25)
+
+[14207503...125907ad](https://github.com/rust-lang/rust-clippy/compare/14207503...125907ad)
+
+* Deprecate `assign_ops` lint
+* New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`],
+  [`needless_collect`], [`copy_iterator`]
+* `cargo clippy -V` now includes the Clippy commit hash of the Rust
+  Clippy component
+* Fix ICE in `implicit_hasher`
+* Fix ICE when encountering `println!("{}" a);`
+* Fix ICE when encountering a macro call in match statements
+* Fix false positive in `default_trait_access`
+* Fix false positive in `trivially_copy_pass_by_ref`
+* Fix false positive in `similar_names`
+* Fix false positive in `redundant_field_name`
+* Fix false positive in `expect_fun_call`
+* Fix false negative in `identity_conversion`
+* Fix false negative in `explicit_counter_loop`
+* Fix `range_plus_one` suggestion and false negative
+* `print_with_newline` / `write_with_newline`: don't warn about string with several `\n`s in them
+* Fix `useless_attribute` to also whitelist `unused_extern_crates`
+* Fix incorrect suggestion for `single_char_pattern`
+* Improve suggestion for `identity_conversion` lint
+* Move `explicit_iter_loop` and `explicit_into_iter_loop` from `style` group to `pedantic`
+* Move `range_plus_one` and `range_minus_one` from `nursery` group to `complexity`
+* Move `shadow_unrelated` from `restriction` group to `pedantic`
+* Move `indexing_slicing` from `pedantic` group to `restriction`
+
+## Rust 1.29 (2018-09-13)
+
+[v0.0.212...14207503](https://github.com/rust-lang/rust-clippy/compare/v0.0.212...14207503)
+
+* :tada: :tada: **Rust 1.29 is the first stable Rust that includes a bundled Clippy** :tada:
+  :tada:
+  You can now run `rustup component add clippy-preview` and then `cargo
+  clippy` to run Clippy. This should put an end to the continuous nightly
+  upgrades for Clippy users.
+* Clippy now follows the Rust versioning scheme instead of its own
+* Fix ICE when encountering a `while let (..) = x.iter()` construct
+* Fix false positives in `use_self`
+* Fix false positive in `trivially_copy_pass_by_ref`
+* Fix false positive in `useless_attribute` lint
+* Fix false positive in `print_literal`
+* Fix `use_self` regressions
+* Improve lint message for `neg_cmp_op_on_partial_ord`
+* Improve suggestion highlight for `single_char_pattern`
+* Improve suggestions for various print/write macro lints
+* Improve website header
+
+## 0.0.212 (2018-07-10)
 * Rustup to *rustc 1.29.0-nightly (e06c87544 2018-07-06)*
 
 ## 0.0.211
@@ -31,7 +235,7 @@ All notable changes to this project will be documented in this file.
 
 ## 0.0.203
 * Rustup to *rustc 1.28.0-nightly (a3085756e 2018-05-19)*
-* clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
+* Clippy attributes are now of the form `clippy::cyclomatic_complexity` instead of `clippy(cyclomatic_complexity)`
 
 ## 0.0.202
 * Rustup to *rustc 1.28.0-nightly (952f344cd 2018-05-18)*
@@ -611,287 +815,321 @@ All notable changes to this project will be documented in this file.
 [`AsMut`]: https://doc.rust-lang.org/std/convert/trait.AsMut.html
 [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
 [configuration file]: ./rust-clippy#configuration
+[pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
+[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
 
 <!-- begin autogenerated links to lint list -->
-[`absurd_extreme_comparisons`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
-[`almost_swapped`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#almost_swapped
-[`approx_constant`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#approx_constant
-[`assign_op_pattern`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#assign_op_pattern
-[`assign_ops`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#assign_ops
-[`bad_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#bad_bit_mask
-[`blacklisted_name`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#blacklisted_name
-[`block_in_if_condition_expr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#block_in_if_condition_expr
-[`block_in_if_condition_stmt`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt
-[`bool_comparison`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#bool_comparison
-[`borrow_interior_mutable_const`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
-[`borrowed_box`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#borrowed_box
-[`box_vec`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#box_vec
-[`boxed_local`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#boxed_local
-[`builtin_type_shadow`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#builtin_type_shadow
-[`cast_lossless`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_lossless
-[`cast_possible_truncation`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_possible_truncation
-[`cast_possible_wrap`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_possible_wrap
-[`cast_precision_loss`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_precision_loss
-[`cast_ptr_alignment`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_ptr_alignment
-[`cast_sign_loss`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_sign_loss
-[`char_lit_as_u8`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#char_lit_as_u8
-[`chars_last_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#chars_last_cmp
-[`chars_next_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#chars_next_cmp
-[`clone_double_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_double_ref
-[`clone_on_copy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_on_copy
-[`clone_on_ref_ptr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
-[`cmp_nan`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cmp_nan
-[`cmp_null`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cmp_null
-[`cmp_owned`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cmp_owned
-[`collapsible_if`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#collapsible_if
-[`const_static_lifetime`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#const_static_lifetime
-[`crosspointer_transmute`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#crosspointer_transmute
-[`cyclomatic_complexity`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cyclomatic_complexity
-[`decimal_literal_representation`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#decimal_literal_representation
-[`declare_interior_mutable_const`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
-[`default_trait_access`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#default_trait_access
-[`deprecated_semver`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#deprecated_semver
-[`deref_addrof`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#deref_addrof
-[`derive_hash_xor_eq`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
-[`diverging_sub_expression`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#diverging_sub_expression
-[`doc_markdown`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#doc_markdown
-[`double_comparisons`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#double_comparisons
-[`double_neg`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#double_neg
-[`double_parens`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#double_parens
-[`drop_copy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#drop_copy
-[`drop_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#drop_ref
-[`duplicate_underscore_argument`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
-[`duration_subsec`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#duration_subsec
-[`else_if_without_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#else_if_without_else
-[`empty_enum`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#empty_enum
-[`empty_line_after_outer_attr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
-[`empty_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#empty_loop
-[`enum_clike_unportable_variant`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
-[`enum_glob_use`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#enum_glob_use
-[`enum_variant_names`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#enum_variant_names
-[`eq_op`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#eq_op
-[`erasing_op`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#erasing_op
-[`eval_order_dependence`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#eval_order_dependence
-[`excessive_precision`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#excessive_precision
-[`expect_fun_call`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#expect_fun_call
-[`expl_impl_clone_on_copy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy
-[`explicit_counter_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#explicit_counter_loop
-[`explicit_into_iter_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#explicit_into_iter_loop
-[`explicit_iter_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#explicit_iter_loop
-[`explicit_write`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#explicit_write
-[`extend_from_slice`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#extend_from_slice
-[`extra_unused_lifetimes`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
-[`fallible_impl_from`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fallible_impl_from
-[`filter_map`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#filter_map
-[`filter_next`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#filter_next
-[`float_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_arithmetic
-[`float_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_cmp
-[`float_cmp_const`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_cmp_const
-[`fn_to_numeric_cast`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
-[`fn_to_numeric_cast_with_truncation`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
-[`for_kv_map`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_kv_map
-[`for_loop_over_option`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_option
-[`for_loop_over_result`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_result
-[`forget_copy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#forget_copy
-[`forget_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#forget_ref
-[`get_unwrap`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#get_unwrap
-[`identity_conversion`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#identity_conversion
-[`identity_op`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#identity_op
-[`if_let_redundant_pattern_matching`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
-[`if_let_some_result`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#if_let_some_result
-[`if_not_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#if_not_else
-[`if_same_then_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#if_same_then_else
-[`ifs_same_cond`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ifs_same_cond
-[`implicit_hasher`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#implicit_hasher
-[`inconsistent_digit_grouping`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
-[`indexing_slicing`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#indexing_slicing
-[`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask
-[`infallible_destructuring_match`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infallible_destructuring_match
-[`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter
-[`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always
-[`inline_fn_without_body`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_fn_without_body
-[`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one
-[`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic
-[`invalid_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_ref
-[`invalid_regex`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_regex
-[`invalid_upcast_comparisons`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
-[`items_after_statements`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#items_after_statements
-[`iter_cloned_collect`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iter_cloned_collect
-[`iter_next_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iter_next_loop
-[`iter_nth`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iter_nth
-[`iter_skip_next`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iter_skip_next
-[`iterator_step_by_zero`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#iterator_step_by_zero
-[`just_underscores_and_digits`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#just_underscores_and_digits
-[`large_digit_groups`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#large_digit_groups
-[`large_enum_variant`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#large_enum_variant
-[`len_without_is_empty`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#len_without_is_empty
-[`len_zero`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#len_zero
-[`let_and_return`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#let_and_return
-[`let_unit_value`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#let_unit_value
-[`linkedlist`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#linkedlist
-[`logic_bug`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#logic_bug
-[`manual_memcpy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#manual_memcpy
-[`manual_swap`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#manual_swap
-[`many_single_char_names`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#many_single_char_names
-[`map_clone`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#map_clone
-[`map_entry`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#map_entry
-[`match_as_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#match_as_ref
-[`match_bool`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#match_bool
-[`match_overlapping_arm`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#match_overlapping_arm
-[`match_ref_pats`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#match_ref_pats
-[`match_same_arms`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#match_same_arms
-[`match_wild_err_arm`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#match_wild_err_arm
-[`maybe_infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#maybe_infinite_iter
-[`mem_forget`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mem_forget
-[`min_max`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#min_max
-[`misaligned_transmute`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#misaligned_transmute
-[`misrefactored_assign_op`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#misrefactored_assign_op
-[`missing_docs_in_private_items`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
-[`missing_inline_in_public_items`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
-[`mixed_case_hex_literals`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
-[`module_inception`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#module_inception
-[`modulo_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#modulo_one
-[`multiple_crate_versions`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#multiple_crate_versions
-[`multiple_inherent_impl`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#multiple_inherent_impl
-[`mut_from_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_from_ref
-[`mut_mut`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_mut
-[`mut_range_bound`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_range_bound
-[`mutex_atomic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mutex_atomic
-[`mutex_integer`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mutex_integer
-[`naive_bytecount`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#naive_bytecount
-[`needless_bool`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_bool
-[`needless_borrow`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_borrow
-[`needless_borrowed_reference`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_borrowed_reference
-[`needless_continue`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_continue
-[`needless_lifetimes`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_lifetimes
-[`needless_pass_by_value`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_pass_by_value
-[`needless_range_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_range_loop
-[`needless_return`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_return
-[`needless_update`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#needless_update
-[`neg_cmp_op_on_partial_ord`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
-[`neg_multiply`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#neg_multiply
-[`never_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#never_loop
-[`new_ret_no_self`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#new_ret_no_self
-[`new_without_default`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#new_without_default
-[`new_without_default_derive`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#new_without_default_derive
-[`no_effect`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#no_effect
-[`non_ascii_literal`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#non_ascii_literal
-[`nonminimal_bool`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#nonminimal_bool
-[`nonsensical_open_options`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#nonsensical_open_options
-[`not_unsafe_ptr_arg_deref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#not_unsafe_ptr_arg_deref
-[`ok_expect`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ok_expect
-[`op_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#op_ref
-[`option_map_or_none`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#option_map_or_none
-[`option_map_unit_fn`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#option_map_unit_fn
-[`option_map_unwrap_or`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#option_map_unwrap_or
-[`option_map_unwrap_or_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#option_map_unwrap_or_else
-[`option_option`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#option_option
-[`option_unwrap_used`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#option_unwrap_used
-[`or_fun_call`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#or_fun_call
-[`out_of_bounds_indexing`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
-[`overflow_check_conditional`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#overflow_check_conditional
-[`panic_params`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#panic_params
-[`panicking_unwrap`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#panicking_unwrap
-[`partialeq_ne_impl`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#partialeq_ne_impl
-[`possible_missing_comma`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#possible_missing_comma
-[`precedence`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#precedence
-[`print_literal`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#print_literal
-[`print_stdout`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#print_stdout
-[`print_with_newline`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#print_with_newline
-[`println_empty_string`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#println_empty_string
-[`ptr_arg`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ptr_arg
-[`pub_enum_variant_names`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#pub_enum_variant_names
-[`question_mark`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#question_mark
-[`range_minus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#range_minus_one
-[`range_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#range_plus_one
-[`range_step_by_zero`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#range_step_by_zero
-[`range_zip_with_len`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#range_zip_with_len
-[`redundant_closure`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#redundant_closure
-[`redundant_closure_call`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#redundant_closure_call
-[`redundant_field_names`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#redundant_field_names
-[`redundant_pattern`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#redundant_pattern
-[`ref_in_deref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ref_in_deref
-[`regex_macro`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#regex_macro
-[`replace_consts`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#replace_consts
-[`result_map_unit_fn`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#result_map_unit_fn
-[`result_map_unwrap_or_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
-[`result_unwrap_used`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#result_unwrap_used
-[`reverse_range_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#reverse_range_loop
-[`search_is_some`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#search_is_some
-[`serde_api_misuse`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#serde_api_misuse
-[`shadow_reuse`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#shadow_reuse
-[`shadow_same`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#shadow_same
-[`shadow_unrelated`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#shadow_unrelated
-[`short_circuit_statement`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#short_circuit_statement
-[`should_assert_eq`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#should_assert_eq
-[`should_implement_trait`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#should_implement_trait
-[`similar_names`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#similar_names
-[`single_char_pattern`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#single_char_pattern
-[`single_match`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#single_match
-[`single_match_else`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#single_match_else
-[`str_to_string`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#str_to_string
-[`string_add`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#string_add
-[`string_add_assign`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#string_add_assign
-[`string_extend_chars`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#string_extend_chars
-[`string_lit_as_bytes`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#string_lit_as_bytes
-[`string_to_string`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#string_to_string
-[`stutter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#stutter
-[`suspicious_arithmetic_impl`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
-[`suspicious_assignment_formatting`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
-[`suspicious_else_formatting`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#suspicious_else_formatting
-[`suspicious_op_assign_impl`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
-[`temporary_assignment`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#temporary_assignment
-[`temporary_cstring_as_ptr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
-[`too_many_arguments`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#too_many_arguments
-[`toplevel_ref_arg`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#toplevel_ref_arg
-[`transmute_bytes_to_str`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
-[`transmute_int_to_bool`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_int_to_bool
-[`transmute_int_to_char`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_int_to_char
-[`transmute_int_to_float`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_int_to_float
-[`transmute_ptr_to_ptr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
-[`transmute_ptr_to_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
-[`trivial_regex`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#trivial_regex
-[`trivially_copy_pass_by_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
-[`type_complexity`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#type_complexity
-[`unicode_not_nfc`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unicode_not_nfc
-[`unimplemented`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unimplemented
-[`unit_arg`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unit_arg
-[`unit_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unit_cmp
-[`unnecessary_cast`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unnecessary_cast
-[`unnecessary_fold`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unnecessary_fold
-[`unnecessary_mut_passed`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
-[`unnecessary_operation`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unnecessary_operation
-[`unnecessary_unwrap`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unnecessary_unwrap
-[`unneeded_field_pattern`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unneeded_field_pattern
-[`unreadable_literal`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unreadable_literal
-[`unsafe_removed_from_name`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
-[`unseparated_literal_suffix`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unseparated_literal_suffix
-[`unstable_as_mut_slice`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
-[`unstable_as_slice`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unstable_as_slice
-[`unused_collect`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unused_collect
-[`unused_io_amount`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unused_io_amount
-[`unused_label`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unused_label
-[`use_debug`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#use_debug
-[`use_self`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#use_self
-[`used_underscore_binding`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#used_underscore_binding
-[`useless_asref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#useless_asref
-[`useless_attribute`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#useless_attribute
-[`useless_format`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#useless_format
-[`useless_let_if_seq`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#useless_let_if_seq
-[`useless_transmute`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#useless_transmute
-[`useless_vec`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#useless_vec
-[`verbose_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#verbose_bit_mask
-[`while_immutable_condition`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#while_immutable_condition
-[`while_let_loop`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#while_let_loop
-[`while_let_on_iterator`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#while_let_on_iterator
-[`write_literal`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#write_literal
-[`write_with_newline`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#write_with_newline
-[`writeln_empty_string`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#writeln_empty_string
-[`wrong_pub_self_convention`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
-[`wrong_self_convention`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#wrong_self_convention
-[`wrong_transmute`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#wrong_transmute
-[`zero_divided_by_zero`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#zero_divided_by_zero
-[`zero_prefixed_literal`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#zero_prefixed_literal
-[`zero_ptr`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#zero_ptr
-[`zero_width_space`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#zero_width_space
+[`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
+[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
+[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
+[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
+[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
+[`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
+[`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
+[`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
+[`block_in_if_condition_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_expr
+[`block_in_if_condition_stmt`]: https://rust-lang.github.io/rust-clippy/master/index.html#block_in_if_condition_stmt
+[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
+[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
+[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
+[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
+[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
+[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
+[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
+[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
+[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
+[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
+[`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
+[`cast_ptr_alignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ptr_alignment
+[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
+[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
+[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
+[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
+[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
+[`clone_double_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref
+[`clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy
+[`clone_on_ref_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_ref_ptr
+[`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
+[`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
+[`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
+[`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
+[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
+[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
+[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
+[`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
+[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
+[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
+[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
+[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
+[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
+[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
+[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
+[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
+[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
+[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
+[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
+[`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
+[`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
+[`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds
+[`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy
+[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
+[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
+[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
+[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
+[`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
+[`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
+[`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
+[`enum_clike_unportable_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_clike_unportable_variant
+[`enum_glob_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_glob_use
+[`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names
+[`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op
+[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
+[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
+[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
+[`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
+[`expl_impl_clone_on_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#expl_impl_clone_on_copy
+[`explicit_counter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_counter_loop
+[`explicit_into_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_into_iter_loop
+[`explicit_iter_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop
+[`explicit_write`]: https://rust-lang.github.io/rust-clippy/master/index.html#explicit_write
+[`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
+[`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
+[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
+[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
+[`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
+[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
+[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
+[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
+[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
+[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
+[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
+[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
+[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
+[`for_loop_over_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_option
+[`for_loop_over_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loop_over_result
+[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
+[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
+[`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
+[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
+[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
+[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
+[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
+[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
+[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`implicit_hasher`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_hasher
+[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
+[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
+[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
+[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
+[`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
+[`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
+[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
+[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
+[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
+[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
+[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
+[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
+[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
+[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
+[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
+[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
+[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
+[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
+[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
+[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
+[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
+[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
+[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
+[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
+[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
+[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
+[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
+[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
+[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
+[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
+[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
+[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
+[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
+[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
+[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
+[`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
+[`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
+[`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
+[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
+[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
+[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
+[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
+[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
+[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
+[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
+[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
+[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
+[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
+[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
+[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
+[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
+[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
+[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
+[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
+[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception
+[`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
+[`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
+[`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
+[`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
+[`mut_from_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
+[`mut_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_mut
+[`mut_range_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#mut_range_bound
+[`mutex_atomic`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_atomic
+[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
+[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
+[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
+[`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
+[`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
+[`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
+[`needless_continue`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_continue
+[`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes
+[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
+[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
+[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
+[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
+[`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
+[`neg_multiply`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_multiply
+[`never_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#never_loop
+[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
+[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
+[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
+[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
+[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
+[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
+[`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_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
+[`option_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or_else
+[`option_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_option
+[`option_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_unwrap_used
+[`or_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call
+[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
+[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
+[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
+[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
+[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
+[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
+[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
+[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
+[`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
+[`print_stdout`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
+[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
+[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
+[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
+[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
+[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
+[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
+[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one
+[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
+[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
+[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
+[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
+[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
+[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
+[`redundant_closure_for_method_calls`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
+[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
+[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
+[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
+[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
+[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
+[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
+[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
+[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
+[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
+[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
+[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
+[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
+[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
+[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
+[`shadow_unrelated`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_unrelated
+[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
+[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
+[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
+[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
+[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
+[`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
+[`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
+[`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
+[`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
+[`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
+[`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
+[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
+[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
+[`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_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
+[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
+[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
+[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
+[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
+[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
+[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
+[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
+[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
+[`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
+[`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
+[`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref
+[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
+[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
+[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
+[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
+[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
+[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
+[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
+[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
+[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
+[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
+[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
+[`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
+[`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
+[`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
+[`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name
+[`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization
+[`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix
+[`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
+[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
+[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
+[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
+[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
+[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
+[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
+[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
+[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
+[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
+[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
+[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
+[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
+[`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
+[`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
+[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
+[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
+[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
+[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
+[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
+[`wildcard_dependencies`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_dependencies
+[`wildcard_enum_match_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_enum_match_arm
+[`write_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_literal
+[`write_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#write_with_newline
+[`writeln_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#writeln_empty_string
+[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
+[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
+[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
+[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
+[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
+[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
+[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 <!-- end autogenerated links to lint list -->
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644 (file)
index 0000000..d70b2b5
--- /dev/null
@@ -0,0 +1,40 @@
+# The Rust Code of Conduct
+
+A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
+
+## Conduct
+
+**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
+
+* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
+* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
+* Please be kind and courteous. There's no need to be mean or rude.
+* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
+* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
+* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
+* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
+* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
+
+## Moderation
+
+
+These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team].
+
+1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
+2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
+3. Moderators will first respond to such remarks with a warning.
+4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
+5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
+6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
+7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
+8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
+
+In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
+
+And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
+
+The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
+
+*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
+
+[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
index 232752c20258bfc1363f9f27b7a79e5e3b569812..3eff20cead74f36cf8acf5498f64db9553becad3 100644 (file)
@@ -14,12 +14,10 @@ All contributors are expected to follow the [Rust Code of Conduct](http://www.ru
 * [Getting started](#getting-started)
   * [Finding something to fix/improve](#finding-something-to-fiximprove)
 * [Writing code](#writing-code)
-  * [Author lint](#author-lint)
-  * [Documentation](#documentation)
-  * [Running test suite](#running-test-suite)
-  * [Testing manually](#testing-manually)
-  * [How Clippy works](#how-clippy-works)
-  * [Fixing nightly build failures](#fixing-nightly-build-failures)
+* [How Clippy works](#how-clippy-works)
+* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust)
+* [Issue and PR Triage](#issue-and-pr-triage)
+* [Bors and Homu](#bors-and-homu)
 * [Contributions](#contributions)
 
 ## Getting started
@@ -35,27 +33,34 @@ High level approach:
 
 All issues on Clippy are mentored, if you want help with a bug just ask @Manishearth, @llogiq, @mcarton or @oli-obk.
 
-Some issues are easier than others. The [`good first issue`](https://github.com/rust-lang-nursery/rust-clippy/labels/good%20first%20issue)
+Some issues are easier than others. The [`good first issue`](https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue)
 label can be used to find the easy issues. If you want to work on an issue, please leave a comment
 so that we can assign it to you!
 
-Issues marked [`T-AST`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-AST) involve simple
+There are also some abandoned PRs, marked with
+[`S-inactive-closed`](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed).
+Pretty often these PRs are nearly completed and just need some extra steps
+(formatting, addressing review comments, ...) to be merged. If you want to
+complete such a PR, please leave a comment in the PR and open a new one based
+on it.
+
+Issues marked [`T-AST`](https://github.com/rust-lang/rust-clippy/labels/T-AST) involve simple
 matching of the syntax tree structure, and are generally easier than
-[`T-middle`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-middle) issues, which involve types
+[`T-middle`](https://github.com/rust-lang/rust-clippy/labels/T-middle) issues, which involve types
 and resolved paths.
 
-[`T-AST`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-AST) issues will generally need you to match against a predefined syntax structure. To figure out
+[`T-AST`](https://github.com/rust-lang/rust-clippy/labels/T-AST) issues will generally need you to match against a predefined syntax structure. To figure out
 how this syntax structure is encoded in the AST, it is recommended to run `rustc -Z ast-json` on an
 example of the structure and compare with the
 [nodes in the AST docs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast). Usually
 the lint will end up to be a nested series of matches and ifs,
-[like so](https://github.com/rust-lang-nursery/rust-clippy/blob/de5ccdfab68a5e37689f3c950ed1532ba9d652a0/src/misc.rs#L34).
+[like so](https://github.com/rust-lang/rust-clippy/blob/de5ccdfab68a5e37689f3c950ed1532ba9d652a0/src/misc.rs#L34).
 
-[`E-medium`](https://github.com/rust-lang-nursery/rust-clippy/labels/E-medium) issues are generally
+[`E-medium`](https://github.com/rust-lang/rust-clippy/labels/E-medium) issues are generally
 pretty easy too, though it's recommended you work on an E-easy issue first. They are mostly classified
 as `E-medium`, since they might be somewhat involved code wise, but not difficult per-se.
 
-[`T-middle`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-middle) issues can
+[`T-middle`](https://github.com/rust-lang/rust-clippy/labels/T-middle) issues can
 be more involved and require verifying types. The
 [`ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty) module contains a
 lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
@@ -63,96 +68,16 @@ an AST expression). `match_def_path()` in Clippy's `utils` module can also be us
 
 ## Writing code
 
-Compiling Clippy from scratch can take almost a minute or more depending on your machine.
-However, since Rust 1.24.0 incremental compilation is enabled by default and compile times for small changes should be quick.
-
-[Llogiq's blog post on lints](https://llogiq.github.io/2015/06/04/workflows.html) is a nice primer
-to lint-writing, though it does get into advanced stuff. Most lints consist of an implementation of
-`LintPass` with one or more of its default methods overridden. See the existing lints for examples
-of this.
-
-
-### Author lint
-
-There is also the internal `author` lint to generate Clippy code that detects the offending pattern. It does not work for all of the Rust syntax, but can give a good starting point.
-
-First, create a new UI test file in the `tests/ui/` directory with the pattern you want to match:
-
-```rust
-// ./tests/ui/my_lint.rs
-fn main() {
-    #[clippy::author]
-    let arr: [i32; 1] = [7]; // Replace line with the code you want to match
-}
-```
-
-Now you run `TESTNAME=ui/my_lint cargo test --test compile-test` to produce
-a `.stdout` file with the generated code:
-
-```rust
-// ./tests/ui/my_lint.stdout
-
-if_chain! {
-    if let ExprKind::Array(ref elements) = stmt.node;
-    if elements.len() == 1;
-    if let ExprKind::Lit(ref lit) = elements[0].node;
-    if let LitKind::Int(7, _) = lit.node;
-    then {
-        // report your lint here
-    }
-}
-```
-
-If the command was executed successfully, you can copy the code over to where you are implementing your lint.
-
-### Documentation
-
-Please document your lint with a doc comment akin to the following:
-
-```rust
-/// **What it does:** Checks for ... (describe what the lint matches).
-///
-/// **Why is this bad?** Supply the reason for linting the code.
-///
-/// **Known problems:** None. (Or describe where it could go wrong.)
-///
-/// **Example:**
-///
-/// ```rust
-/// // Bad
-/// Insert a short example of code that triggers the lint
-///
-/// // Good
-/// Insert a short example of improved code that doesn't trigger the lint
-/// ```
-```
-
-Once your lint is merged it will show up in the [lint list](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
+Have a look at the [docs for writing lints](doc/adding_lints.md) for more details. [Llogiq's blog post on lints](https://llogiq.github.io/2015/06/04/workflows.html) is also a nice primer
+to lint-writing, though it does get into advanced stuff and may be a bit
+outdated.
 
-### Running test suite
+If you want to add a new lint or change existing ones apart from bugfixing, it's
+also a good idea to give the [stability guarantees][rfc_stability] and
+[lint categories][rfc_lint_cats] sections of the [Clippy 1.0 RFC][clippy_rfc] a
+quick read.
 
-Use `cargo test` to run the whole testsuite.
-
-If you don't want to wait for all tests to finish, you can also execute a single test file by using `TESTNAME` to specify the test to run:
-
-```bash
-TESTNAME=ui/empty_line_after_outer_attr cargo test --test compile-test
-```
-
-Clippy uses UI tests. UI tests check that the output of the compiler is exactly as expected.
-Of course there's little sense in writing the output yourself or copying it around.
-Therefore you should use `tests/ui/update-all-references.sh` (after running
-`cargo test`) and check whether the output looks as you expect with `git diff`. Commit all
-`*.stderr` files, too.
-
-### Testing manually
-
-Manually testing against an example file is useful if you have added some
-`println!`s and test suite output becomes unreadable.  To try Clippy with your
-local modifications, run `cargo run --bin clippy-driver -- -L ./target/debug input.rs` from the
-working copy root.
-
-### How Clippy works
+## How Clippy works
 
 Clippy is a [rustc compiler plugin][compiler_plugin]. The main entry point is at [`src/lib.rs`][main_entry]. In there, the lint registration is delegated to the [`clippy_lints`][lint_crate] crate.
 
@@ -170,7 +95,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
     reg.register_early_lint_pass(box else_if_without_else::ElseIfWithoutElse);
     // ...
 
-    reg.register_lint_group("clippy_restriction", vec![
+    reg.register_lint_group("clippy::restriction", vec![
         // ...
         else_if_without_else::ELSE_IF_WITHOUT_ELSE,
         // ...
@@ -180,12 +105,12 @@ 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].
 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/update_lints.py` and you don't have to add anything by hand. When you are writing your own lint, you can use that script to save you some time.
+It's worth noting that the majority of `clippy_lints/src/lib.rs` is autogenerated by `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.
 
 ```rust
 // ./clippy_lints/src/else_if_without_else.rs
 
-use rustc::lint::*;
+use rustc::lint::{EarlyLintPass, LintArray, LintPass};
 
 // ...
 
@@ -202,16 +127,55 @@ The difference between `EarlyLintPass` and `LateLintPass` is that the methods of
 
 That's why the `else_if_without_else` example uses the `register_early_lint_pass` function. Because the [actual lint logic][else_if_without_else] does not depend on any type information.
 
-### Fixing nightly build failures
+## Fixing build failures caused by Rust
 
-Clippy will sometimes break with new nightly version releases. This is expected because Clippy still depends on nightly Rust. Most of the times we have to adapt to the changes and only very rarely there's an actual bug in rust.
+Clippy will sometimes fail to build from source because building it depends on unstable internal Rust features. Most of the times we have to adapt to the changes and only very rarely there's an actual bug in Rust. Fixing build failures caused by Rust updates, can be a good way to learn about Rust internals.
 
-In order to find out why Clippy does not work properly with a new nightly version, you can use the [rust-toolstate commit history][toolstate_commit_history].
+In order to find out why Clippy does not work properly with a new Rust commit, you can use the [rust-toolstate commit history][toolstate_commit_history].
 You will then have to look for the last commit that contains `test-pass -> build-fail` or `test-pass` -> `test-fail` for the `clippy-driver` component. [Here][toolstate_commit] is an example.
 
 The commit message contains a link to the PR. The PRs are usually small enough to discover the breaking API change and if they are bigger, they likely include some discussion that may help you to fix Clippy.
 
-Fixing nightly build failures is also a good way to learn about actual rustc internals.
+To check if Clippy is available for a specific target platform, you can check
+the [rustup component history][rustup_component_history].
+
+If you decide to make Clippy work again with a Rust commit that breaks it,
+you probably want to install the latest Rust from master locally and run Clippy
+using that version of Rust.
+
+You can use [rustup-toolchain-install-master][rtim] to do that:
+
+```
+cargo install rustup-toolchain-install-master
+rustup-toolchain-install-master -n master --force
+rustup override set master
+cargo test
+```
+
+## Issue and PR triage
+
+Clippy is following the [Rust triage procedure][triage] for issues and pull
+requests.
+
+However, we are a smaller project with all contributors being volunteers
+currently. Between writing new lints, fixing issues, reviewing pull requests and
+responding to issues there may not always be enough time to stay on top of it
+all.
+
+Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug]. We don't
+want Clippy to crash on your code and we want it to be as reliable as the
+suggestions from Rust compiler errors.
+
+## Bors and Homu
+
+We use a bot powered by [Homu][homu] to help automate testing and landing of pull
+requests in Clippy. The bot's username is @bors.
+
+You can find the Clippy bors queue [here][homu_queue].
+
+If you have @bors permissions, you can find an overview of the available
+commands [here][homu_instructions].
+
 
 ## Contributions
 
@@ -219,14 +183,15 @@ Contributions to Clippy should be made in the form of GitHub pull requests. Each
 be reviewed by a core contributor (someone with permission to land patches) and either landed in the
 main tree or given feedback for changes that would be required.
 
-All code in this repository is under the [Mozilla Public License, 2.0](https://www.mozilla.org/MPL/2.0/)
+All code in this repository is under the [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0>)
+or the [MIT](http://opensource.org/licenses/MIT) license.
 
 <!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->
 
-[main_entry]: https://github.com/rust-lang-nursery/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/src/lib.rs#L14
-[lint_crate]: https://github.com/rust-lang-nursery/rust-clippy/tree/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src
-[lint_crate_entry]: https://github.com/rust-lang-nursery/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/lib.rs
-[else_if_without_else]: https://github.com/rust-lang-nursery/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src/else_if_without_else.rs
+[main_entry]: https://github.com/rust-lang/rust-clippy/blob/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/src/lib.rs#L14
+[lint_crate]: https://github.com/rust-lang/rust-clippy/tree/c5b39a5917ffc0f1349b6e414fa3b874fdcf8429/clippy_lints/src
+[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
@@ -235,3 +200,14 @@ All code in this repository is under the [Mozilla Public License, 2.0](https://w
 [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
 [toolstate_commit]: https://github.com/rust-lang-nursery/rust-toolstate/commit/6ce0459f6bfa7c528ae1886492a3e0b5ef0ee547
+[rtim]: https://github.com/kennytm/rustup-toolchain-install-master
+[rustup_component_history]: https://mexus.github.io/rustup-components-history
+[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
+[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
+[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
+[triage]: https://forge.rust-lang.org/triage-procedure.html
+[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash%20%3Aboom%3A
+[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug%20%3Abeetle%3A
+[homu]: https://github.com/servo/homu
+[homu_instructions]: https://buildbot2.rust-lang.org/homu/
+[homu_queue]: https://buildbot2.rust-lang.org/homu/queue/clippy
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..e507fb8
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,7 @@
+Copyright 2014-2019 The Rust Project Developers
+
+Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+option. All files in the project carrying such notice may not be
+copied, modified, or distributed except according to those terms.
index 798b713a07f67b2a76562588f79c3df08f50c63a..4c1b77c256c99282ad766fd0f618e92411d36b5f 100644 (file)
@@ -1,5 +1,3 @@
-cargo-features = ["edition"]
-
 [package]
 name = "clippy"
 version = "0.0.212"
@@ -11,17 +9,18 @@ authors = [
        "Oliver Schneider <clippy-iethah7aipeen8neex1a@oli-obk.de>"
 ]
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
-repository = "https://github.com/rust-lang-nursery/rust-clippy"
+repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
-license = "MPL-2.0"
+license = "MIT/Apache-2.0"
 keywords = ["clippy", "lint", "plugin"]
 categories = ["development-tools", "development-tools::cargo-plugins"]
 build = "build.rs"
 edition = "2018"
+publish = false
 
 [badges]
-travis-ci = { repository = "rust-lang-nursery/rust-clippy" }
-appveyor = { repository = "rust-lang-nursery/rust-clippy" }
+travis-ci = { repository = "rust-lang/rust-clippy" }
+appveyor = { repository = "rust-lang/rust-clippy" }
 
 [lib]
 name = "clippy"
@@ -35,7 +34,6 @@ path = "src/main.rs"
 
 [[bin]]
 name = "clippy-driver"
-test = false
 path = "src/driver.rs"
 
 [dependencies]
@@ -44,14 +42,14 @@ clippy_lints = { version = "0.0.212", path = "clippy_lints" }
 # end automatic update
 regex = "1"
 semver = "0.9"
+rustc_tools_util = { version = "0.1.1", path = "rustc_tools_util"}
 
 [dev-dependencies]
-cargo_metadata = "0.5"
-compiletest_rs = "0.3.7"
+cargo_metadata = "0.7.1"
+compiletest_rs = { version = "0.3.22", features = ["tmp"] }
 lazy_static = "1.0"
-serde_derive = "1.0"
 clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
-serde = "1.0"
+serde = { version = "1.0", features = ["derive"] }
 derive-new = "0.5"
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
@@ -59,5 +57,8 @@ derive-new = "0.5"
 # for more information.
 rustc-workspace-hack = "1.0.0"
 
+[build-dependencies]
+rustc_tools_util = { version = "0.1.1", path = "rustc_tools_util"}
+
 [features]
 debugging = []
diff --git a/LICENSE b/LICENSE
deleted file mode 100644 (file)
index a612ad9..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,373 +0,0 @@
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..16fe87b
--- /dev/null
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644 (file)
index 0000000..31aa793
--- /dev/null
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
index 749eae973047af002ef3b3f2c70a655d8184570d..b85605dc3b316f64d4f5ccd7eac6d0f909e98876 100644 (file)
@@ -2,7 +2,6 @@ Steps to publish a new Clippy version
 
 - Bump `package.version` in `./Cargo.toml` (no need to manually bump `dependencies.clippy_lints.version`).
 - Write a changelog entry.
-- If a nightly update is needed, update `min_version.txt` using `rustc -vV > min_version.txt`
 - Run `./pre_publish.sh`
 - Review and commit all changed files
 - `git push`
index 41eacdba1a4a81f0a49e0c48688ac0c6a6553716..e670924de2b174faed593a45a8d1ecd01939245c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,28 +1,37 @@
-We are currently in the process of discussing Clippy 1.0 via the RFC process in https://github.com/rust-lang/rfcs/pull/2476 . The RFC's goal is to clarify policies around lint categorizations and the policy around which lints should be in the compiler and which lints should be in Clippy. Please leave your thoughts on the RFC PR.
-
 # Clippy
 
-[![Build Status](https://travis-ci.org/rust-lang-nursery/rust-clippy.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/rust-clippy)
+[![Build Status](https://travis-ci.com/rust-lang/rust-clippy.svg?branch=master)](https://travis-ci.com/rust-lang/rust-clippy)
 [![Windows Build status](https://ci.appveyor.com/api/projects/status/id677xpw1dguo7iw?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rust-clippy)
 [![Current Version](https://meritbadge.herokuapp.com/clippy)](https://crates.io/crates/clippy)
-[![License: MPL-2.0](https://img.shields.io/crates/l/clippy.svg)](#license)
+[![License: MIT/Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](#license)
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are 273 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
+[There are 302 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:
 
-* `clippy` (everything that has no false positives)
-* `clippy_pedantic` (everything)
-* `clippy_nursery` (new lints that aren't quite ready yet)
-* `clippy_style` (code that should be written in a more idiomatic way)
-* `clippy_complexity` (code that does something simple but in a complex way)
-* `clippy_perf` (code that can be written in a faster way)
-* `clippy_cargo` (checks against the cargo manifest)
-* **`clippy_correctness`** (code that is just outright wrong or very very useless)
+* `clippy::all` (everything that is on by default: all the categories below except for `nursery`, `pedantic`, and `cargo`)
+* **`clippy::correctness`** (code that is just outright wrong or very very useless, causes hard errors by default)
+* `clippy::style` (code that should be written in a more idiomatic way)
+* `clippy::complexity` (code that does something simple but in a complex way)
+* `clippy::perf` (code that can be written in a faster way)
+* `clippy::pedantic` (lints which are rather strict, off by default)
+* `clippy::nursery` (new lints that aren't quite ready yet, off by default)
+* `clippy::cargo` (checks against the cargo manifest, off by default)
+
+More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas!
+
+Only the following of those categories are enabled by default:
+
+* `clippy::style`
+* `clippy::correctness`
+* `clippy::complexity`
+* `clippy::perf`
+
+Other categories need to be enabled in order for their lints to be executed.
 
-More to come, please [file an issue](https://github.com/rust-lang-nursery/rust-clippy/issues) if you have ideas!
+The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used very selectively, if at all.
 
 Table of contents:
 
@@ -45,7 +54,7 @@ subcommand.
 #### Step 1: Install rustup
 
 You can install [rustup](http://rustup.rs/) on supported platforms. This will help
-us install clippy and its dependencies.
+us install Clippy and its dependencies.
 
 If you already have rustup installed, update to ensure you have the latest
 rustup and compiler:
@@ -54,27 +63,23 @@ rustup and compiler:
 rustup update
 ```
 
-#### Step 2: Install nightly toolchain
+#### Step 2: Install Clippy
 
-Rustup integration is still new, you will need a relatively new nightly (2018-07-15 or later).
-
-To install Rust nightly with [rustup](https://rustup.rs/):
+Once you have rustup and the latest stable release (at least Rust 1.29) installed, run the following command:
 
 ```terminal
-rustup install nightly
+rustup component add clippy
 ```
+If it says that it can't find the `clippy` component, please run `rustup self update`.
 
-#### Step 3: Install clippy
+#### Step 3: Run Clippy
 
-Once you have rustup and the nightly toolchain installed, run the following command:
+Now you can run Clippy by invoking the following command:
 
 ```terminal
-rustup component add clippy-preview --toolchain=nightly
+cargo clippy
 ```
 
-Now you can run Clippy by invoking `cargo +nightly clippy`. If nightly is your
-default toolchain in rustup, `cargo clippy` will work fine.
-
 ### Running Clippy from the command line without installing it
 
 To have cargo compile your crate with Clippy without Clippy installation
@@ -84,19 +89,57 @@ in your code, you can use:
 cargo run --bin cargo-clippy --manifest-path=path_to_clippys_Cargo.toml
 ```
 
-*[Note](https://github.com/rust-lang-nursery/rust-clippy/wiki#a-word-of-warning):*
+*[Note](https://github.com/rust-lang/rust-clippy/wiki#a-word-of-warning):*
 Be sure that Clippy was compiled with the same version of rustc that cargo invokes here!
 
+### Travis CI
+
+You can add Clippy to Travis CI in the same way you use it locally:
+
+```yml
+language: rust
+rust:
+  - stable
+  - beta
+before_script:
+  - rustup component add clippy
+script:
+  - cargo clippy
+  # if you want the build job to fail when encountering warnings, use
+  - cargo clippy -- -D warnings
+  # in order to also check tests and non-default crate features, use
+  - cargo clippy --all-targets --all-features -- -D warnings
+  - cargo test
+  # etc.
+```
+
+If you are on nightly, It might happen that Clippy is not available for a certain nightly release.
+In this case you can try to conditionally install Clippy from the git repo.
+
+```yaml
+language: rust
+rust:
+  - nightly
+before_script:
+   - rustup component add clippy --toolchain=nightly || cargo install --git https://github.com/rust-lang/rust-clippy/ --force clippy
+   # etc
+```
+
+Note that adding `-D warnings` will cause your build to fail if **any** warnings are found in your code.
+That includes warnings found by rustc (e.g. `dead_code`, etc.). If you want to avoid this and only cause
+an error for clippy warnings, use `#![deny(clippy::all)]` in your code or `-D clippy::all` on the command
+line. (You can swap `clippy::all` with the specific lint category you are targeting.)
+
 ## Configuration
 
-Some lints can be configured in a TOML file named with `clippy.toml` or `.clippy.toml`. It contains basic `variable = value` mapping eg.
+Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml`. It contains a basic `variable = value` mapping eg.
 
 ```toml
 blacklisted-names = ["toto", "tata", "titi"]
-cyclomatic-complexity-threshold = 30
+cognitive-complexity-threshold = 30
 ```
 
-See the [list of lints](https://rust-lang-nursery.github.io/rust-clippy/master/index.html) for more information about which lints can be configured and the
+See the [list of lints](https://rust-lang.github.io/rust-clippy/master/index.html) for more information about which lints can be configured and the
 meaning of the variables.
 
 To deactivate the “for further information visit *lint-link*” message you can
@@ -104,38 +147,32 @@ define the `CLIPPY_DISABLE_DOCS_LINKS` environment variable.
 
 ### Allowing/denying lints
 
-You can add options  to `allow`/`warn`/`deny`:
+You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
 
-*   the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy)]`)
+*   the whole set of `Warn` lints using the `clippy` lint group (`#![deny(clippy::all)]`)
 
-*   all lints using both the `clippy` and `clippy_pedantic` lint groups (`#![deny(clippy)]`,
-    `#![deny(clippy_pedantic)]`). Note that `clippy_pedantic` contains some very aggressive
+*   all lints using both the `clippy` and `clippy::pedantic` lint groups (`#![deny(clippy::all)]`,
+    `#![deny(clippy::pedantic)]`). Note that `clippy::pedantic` contains some very aggressive
     lints prone to false positives.
 
-*   only some lints (`#![deny(single_match, box_vec)]`, etc)
+*   only some lints (`#![deny(clippy::single_match, clippy::box_vec)]`, etc)
 
 *   `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc
 
 Note: `deny` produces errors instead of warnings.
 
-For convenience, `cargo clippy` automatically defines a `cargo-clippy`
-feature. This lets you set lint levels and compile with or without Clippy
-transparently:
+If you do not want to include your lint levels in your code, you can globally enable/disable lints by passing extra flags to Clippy during the run: `cargo clippy -- -A clippy::lint_name` will run Clippy with `lint_name` disabled and `cargo clippy -- -W clippy::lint_name` will run it with that enabled. This also works with lint groups. For example you can run Clippy with warnings for all lints enabled: `cargo clippy -- -W clippy::pedantic`
 
-```rust
-#[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
-```
-
-## Updating rustc
+## Contributing
 
-Sometimes, rustc moves forward without Clippy catching up. Therefore updating
-rustc may leave Clippy a non-functional state until we fix the resulting
-breakage.
-
-You can use the [rust-update](rust-update) script to update rustc only if
-Clippy would also update correctly.
+If you want to contribute to Clippy, you can find more information in [CONTRIBUTING.md](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md).
 
 ## License
 
-Licensed under [MPL](https://www.mozilla.org/MPL/2.0/).
-If you're having issues with the license, let me know and I'll try to change it to something more permissive.
+Copyright 2014-2019 The Rust Project Developers
+
+Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+option. All files in the project carrying such notice may not be
+copied, modified, or distributed except according to those terms.
index 32ea8c62a2de617f00d09ad1449cf222b32e0a16..2d8704a703bcd6655e7fb2c30215d1306dfec939 100644 (file)
@@ -3,20 +3,28 @@ environment:
         PROJECT_NAME: rust-clippy
     matrix:
         #- TARGET: i686-pc-windows-gnu
-        #  MSYS2_BITS: 32
         #- TARGET: i686-pc-windows-msvc
-        #  MSYS2_BITS: 32
         #- TARGET: x86_64-pc-windows-gnu
-        #  MSYS2_BITS: 64
         - TARGET: x86_64-pc-windows-msvc
-          MSYS2_BITS: 64
+
+branches:
+    # Only build AppVeyor on r+, try and the master branch
+    only:
+      - auto
+      - try
+      - master
 
 install:
-    - set PATH=C:\Program Files\Git\mingw64\bin;%PATH%
     - curl -sSf -o rustup-init.exe https://win.rustup.rs/
     - rustup-init.exe -y --default-host %TARGET% --default-toolchain nightly
-    - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin;C:\Users\appveyor\.rustup\toolchains\nightly-%TARGET%\bin
-    - if defined MSYS2_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS2_BITS%\bin
+    - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+    - git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}' >rustc-hash.txt
+    - set /p RUSTC_HASH=<rustc-hash.txt
+    - del rust-toolchain
+    - cargo install rustup-toolchain-install-master --debug || echo "rustup-toolchain-install-master already installed"
+    - rustup-toolchain-install-master %RUSTC_HASH% -f -n master
+    - rustup default master
+    - set PATH=%PATH%;C:\Users\appveyor\.rustup\toolchains\master\bin
     - rustc -V
     - cargo -V
 
@@ -26,9 +34,6 @@ test_script:
     - set RUST_BACKTRACE=1
     - cargo build --features debugging
     - cargo test --features debugging
-    #- copy target\debug\cargo-clippy.exe C:\Users\appveyor\.cargo\bin\
-    #- cargo clippy -- -D clippy
-    #- cd clippy_lints && cargo clippy -- -D clippy && cd ..
 
 notifications:
     - provider: Email
index 3b9f217c8848fa968dd5a70092ad2284c0f7ad78..146a8dae74596a25c5042447e846f4a38c1888c2 100644 (file)
--- a/build.rs
+++ b/build.rs
@@ -1,23 +1,15 @@
-//! This build script ensures that Clippy is not compiled with an
-//! incompatible version of rust. It will panic with a descriptive
-//! error message instead.
-//!
-//! We specifially want to ensure that Clippy is only built with a
-//! rustc version that is newer or equal to the one specified in the
-//! `min_version.txt` file.
-//!
-//! `min_version.txt` is in the repo but also in the `.gitignore` to
-//! make sure that it is not updated manually by accident. Only CI
-//! should update that file.
-//!
-//! This build script was originally taken from the Rocket web framework:
-//! https://github.com/SergioBenitez/Rocket
-
-use std::env;
-
 fn main() {
     // Forward the profile to the main compilation
-    println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
+    println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());
     // Don't rebuild even if nothing changed
     println!("cargo:rerun-if-changed=build.rs");
+    // forward git repo hashes we build at
+    println!(
+        "cargo:rustc-env=GIT_HASH={}",
+        rustc_tools_util::get_commit_hash().unwrap_or_default()
+    );
+    println!(
+        "cargo:rustc-env=COMMIT_DATE={}",
+        rustc_tools_util::get_commit_date().unwrap_or_default()
+    );
 }
index 13b652c0f7dd6139a60fac1d67bb4c75f6423576..64214e3be8651550e53ff2043263818d6bb15e3a 100755 (executable)
@@ -3,22 +3,78 @@ set -ex
 echo "Running clippy base tests"
 
 PATH=$PATH:./node_modules/.bin
-remark -f *.md > /dev/null
+if [ "$TRAVIS_OS_NAME" == "linux" ]; then
+  remark -f *.md -f doc/*.md > /dev/null
+fi
 # build clippy in debug mode and run tests
 cargo build --features debugging
 cargo test --features debugging
-mkdir -p ~/rust/cargo/bin
-cp target/debug/cargo-clippy ~/rust/cargo/bin/cargo-clippy
-cp target/debug/clippy-driver ~/rust/cargo/bin/clippy-driver
-rm ~/.cargo/bin/cargo-clippy
-# run clippy on its own codebase...
-PATH=$PATH:~/rust/cargo/bin cargo clippy --all-targets --all-features -- -D clippy
-# ... and some test directories
-cd clippy_workspace_tests && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ..
-cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../..
-cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../..
-cd clippy_workspace_tests/subcrate/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../../..
-# test --manifest-path
-PATH=$PATH:~/rust/cargo/bin cargo clippy --manifest-path=clippy_workspace_tests/Cargo.toml -- -D clippy
-cd clippy_workspace_tests/subcrate && PATH=$PATH:~/rust/cargo/bin cargo clippy --manifest-path=../Cargo.toml -- -D clippy && cd ../..
-set +x
+# for faster build, share target dir between subcrates
+export CARGO_TARGET_DIR=`pwd`/target/
+(cd clippy_lints && cargo test)
+(cd rustc_tools_util && cargo test)
+(cd clippy_dev && cargo test)
+
+# make sure clippy can be called via ./path/to/cargo-clippy
+(
+  cd clippy_workspace_tests
+  ../target/debug/cargo-clippy
+)
+
+# Perform various checks for lint registration
+./util/dev update_lints --check
+cargo +nightly fmt --all -- --check
+
+# Check running clippy-driver without cargo
+(
+  export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib
+
+  # Check sysroot handling
+  sysroot=$(./target/debug/clippy-driver --print sysroot)
+  test $sysroot = $(rustc --print sysroot)
+
+  sysroot=$(./target/debug/clippy-driver --sysroot /tmp --print sysroot)
+  test $sysroot = /tmp
+
+  sysroot=$(SYSROOT=/tmp ./target/debug/clippy-driver --print sysroot)
+  test $sysroot = /tmp
+
+  # Make sure this isn't set - clippy-driver should cope without it
+  unset CARGO_MANIFEST_DIR
+
+  # Run a lint and make sure it produces the expected output. It's also expected to exit with code 1
+  # XXX How to match the clippy invocation in compile-test.rs?
+  ! ./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/cstring.rs 2> cstring.stderr
+  diff <(sed -e 's,tests/ui,$DIR,' -e '/= help/d' cstring.stderr) tests/ui/cstring.stderr
+
+  # TODO: CLIPPY_CONF_DIR / CARGO_MANIFEST_DIR
+)
+
+# make sure tests are formatted
+
+# some lints are sensitive to formatting, exclude some files
+tests_need_reformatting="false"
+# switch to nightly
+rustup override set nightly
+# avoid loop spam and allow cmds with exit status != 0
+set +ex
+
+# Excluding `ice-3891.rs` because the code triggers a rustc parse error which
+# makes rustfmt fail.
+for file in `find tests -not -path "tests/ui/crashes/ice-3891.rs" | grep "\.rs$"` ; do
+  rustfmt ${file} --check
+  if [ $? -ne 0 ]; then
+    echo "${file} needs reformatting!"
+    tests_need_reformatting="true"
+  fi
+done
+
+set -ex # reset
+
+if [ "${tests_need_reformatting}" == "true" ] ; then
+    echo "Tests need reformatting!"
+    exit 2
+fi
+
+# switch back to master
+rustup override set master
index ac0d2f1614ba189ccdeb7ae1ac168cc6b42a8e69..1259c5e1d37892f8afdca72ade984611225fcd0e 100755 (executable)
@@ -9,18 +9,15 @@ cd checkout
 
 function check() {
 # run clippy on a project, try to be verbose and trigger as many warnings as possible for greater coverage
-  RUST_BACKTRACE=full cargo clippy --all-targets --all-features -- --cap-lints warn -W clippy_pedantic -W clippy_nursery  &> clippy_output
+  RUST_BACKTRACE=full cargo clippy --all-targets --all-features -- --cap-lints warn -W clippy::pedantic -W clippy::nursery  &> clippy_output
   cat clippy_output
-  ! cat clippy_output | grep -q "internal compiler error\|query stack during panic"
+  ! cat clippy_output | grep -q "internal compiler error\|query stack during panic\|E0463"
   if [[ $? != 0 ]]; then
     return 1
   fi
 }
 
 case ${INTEGRATION} in
-  rust-lang/cargo)
-    check
-    ;;
   *)
     check
     ;;
diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml
new file mode 100644 (file)
index 0000000..3b4a11a
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+name = "clippy_dev"
+version = "0.0.1"
+authors = ["Philipp Hansch <dev@phansch.net>"]
+edition = "2018"
+
+[dependencies]
+clap = "~2.32"
+itertools = "0.8"
+regex = "1"
+lazy_static = "1.0"
+walkdir = "2"
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
new file mode 100644 (file)
index 0000000..392388f
--- /dev/null
@@ -0,0 +1,487 @@
+use itertools::Itertools;
+use lazy_static::lazy_static;
+use regex::Regex;
+use std::collections::HashMap;
+use std::ffi::OsStr;
+use std::fs;
+use std::io::prelude::*;
+use walkdir::WalkDir;
+
+lazy_static! {
+    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(
+        r#"(?x)
+        declare_clippy_lint!\s*[\{(]
+        (?:\s+///.*)*
+        \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
+        (?P<cat>[a-z_]+)\s*,\s*
+        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
+    "#
+    )
+    .unwrap();
+    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(
+        r#"(?x)
+        declare_deprecated_lint!\s*[{(]\s*
+        (?:\s+///.*)*
+        \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
+        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
+    "#
+    )
+    .unwrap();
+    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
+    pub static ref DOCS_LINK: String = "https://rust-lang.github.io/rust-clippy/master/index.html".to_string();
+}
+
+/// Lint data parsed from the Clippy source code.
+#[derive(Clone, PartialEq, Debug)]
+pub struct Lint {
+    pub name: String,
+    pub group: String,
+    pub desc: String,
+    pub deprecation: Option<String>,
+    pub module: String,
+}
+
+impl Lint {
+    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Self {
+        Self {
+            name: name.to_lowercase(),
+            group: group.to_string(),
+            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
+            deprecation: deprecation.map(std::string::ToString::to_string),
+            module: module.to_string(),
+        }
+    }
+
+    /// Returns all non-deprecated lints and non-internal lints
+    pub fn usable_lints(lints: impl Iterator<Item = Self>) -> impl Iterator<Item = Self> {
+        lints.filter(|l| l.deprecation.is_none() && !l.is_internal())
+    }
+
+    /// Returns the lints in a HashMap, grouped by the different lint groups
+    pub fn by_lint_group(lints: &[Self]) -> HashMap<String, Vec<Self>> {
+        lints
+            .iter()
+            .map(|lint| (lint.group.to_string(), lint.clone()))
+            .into_group_map()
+    }
+
+    pub fn is_internal(&self) -> bool {
+        self.group.starts_with("internal")
+    }
+}
+
+/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
+pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
+    lints
+        .into_iter()
+        .filter_map(|l| {
+            if l.is_internal() || l.deprecation.is_some() {
+                None
+            } else {
+                Some(format!("        {}::{},", l.module, l.name.to_uppercase()))
+            }
+        })
+        .sorted()
+        .collect::<Vec<String>>()
+}
+
+/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
+pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
+    lints
+        .into_iter()
+        .filter_map(|l| {
+            if l.is_internal() || l.deprecation.is_some() {
+                None
+            } else {
+                Some(l.module)
+            }
+        })
+        .unique()
+        .map(|module| format!("pub mod {};", module))
+        .sorted()
+        .collect::<Vec<String>>()
+}
+
+/// Generates the list of lint links at the bottom of the README
+pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
+    let mut lint_list_sorted: Vec<Lint> = lints;
+    lint_list_sorted.sort_by_key(|l| l.name.clone());
+    lint_list_sorted
+        .iter()
+        .filter_map(|l| {
+            if l.is_internal() {
+                None
+            } else {
+                Some(format!("[`{}`]: {}#{}", l.name, DOCS_LINK.clone(), l.name))
+            }
+        })
+        .collect()
+}
+
+/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
+pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
+    lints
+        .iter()
+        .filter_map(|l| {
+            l.clone().deprecation.and_then(|depr_text| {
+                Some(vec![
+                    "    store.register_removed(".to_string(),
+                    format!("        \"{}\",", l.name),
+                    format!("        \"{}\",", depr_text),
+                    "    );".to_string(),
+                ])
+            })
+        })
+        .flatten()
+        .collect::<Vec<String>>()
+}
+
+/// Gathers all files in `src/clippy_lints` and gathers all lints inside
+pub fn gather_all() -> impl Iterator<Item = Lint> {
+    lint_files().flat_map(|f| gather_from_file(&f))
+}
+
+fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item = Lint> {
+    let mut file = fs::File::open(dir_entry.path()).unwrap();
+    let mut content = String::new();
+    file.read_to_string(&mut content).unwrap();
+    let mut filename = dir_entry.path().file_stem().unwrap().to_str().unwrap();
+    // If the lints are stored in mod.rs, we get the module name from
+    // the containing directory:
+    if filename == "mod" {
+        filename = dir_entry
+            .path()
+            .parent()
+            .unwrap()
+            .file_stem()
+            .unwrap()
+            .to_str()
+            .unwrap()
+    }
+    parse_contents(&content, filename)
+}
+
+fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item = Lint> {
+    let lints = DEC_CLIPPY_LINT_RE
+        .captures_iter(content)
+        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename));
+    let deprecated = DEC_DEPRECATED_LINT_RE
+        .captures_iter(content)
+        .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename));
+    // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
+    lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
+}
+
+/// Collects all .rs files in the `clippy_lints/src` directory
+fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> {
+    // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
+    // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`.
+    WalkDir::new("../clippy_lints/src")
+        .into_iter()
+        .filter_map(std::result::Result::ok)
+        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
+}
+
+/// Whether a file has had its text changed or not
+#[derive(PartialEq, Debug)]
+pub struct FileChange {
+    pub changed: bool,
+    pub new_lines: String,
+}
+
+/// Replaces a region in a file delimited by two lines matching regexes.
+///
+/// `path` is the relative path to the file on which you want to perform the replacement.
+///
+/// See `replace_region_in_text` for documentation of the other options.
+#[allow(clippy::expect_fun_call)]
+pub fn replace_region_in_file<F>(
+    path: &str,
+    start: &str,
+    end: &str,
+    replace_start: bool,
+    write_back: bool,
+    replacements: F,
+) -> FileChange
+where
+    F: Fn() -> Vec<String>,
+{
+    let mut f = fs::File::open(path).expect(&format!("File not found: {}", path));
+    let mut contents = String::new();
+    f.read_to_string(&mut contents)
+        .expect("Something went wrong reading the file");
+    let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
+
+    if write_back {
+        let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
+        f.write_all(file_change.new_lines.as_bytes())
+            .expect("Unable to write file");
+        // Ensure we write the changes with a trailing newline so that
+        // the file has the proper line endings.
+        f.write_all(b"\n").expect("Unable to write file");
+    }
+    file_change
+}
+
+/// Replaces a region in a text delimited by two lines matching regexes.
+///
+/// * `text` is the input text on which you want to perform the replacement
+/// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
+///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
+/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen.
+///   As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
+/// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end`
+///   delimiter line is never replaced.
+/// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
+///
+/// If you want to perform the replacement on files instead of already parsed text,
+/// use `replace_region_in_file`.
+///
+/// # Example
+///
+/// ```
+/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
+/// let result = clippy_dev::replace_region_in_text(the_text, r#"replace_start"#, r#"replace_end"#, false, || {
+///     vec!["a different".to_string(), "text".to_string()]
+/// })
+/// .new_lines;
+/// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
+/// ```
+pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange
+where
+    F: Fn() -> Vec<String>,
+{
+    let lines = text.lines();
+    let mut in_old_region = false;
+    let mut found = false;
+    let mut new_lines = vec![];
+    let start = Regex::new(start).unwrap();
+    let end = Regex::new(end).unwrap();
+
+    for line in lines.clone() {
+        if in_old_region {
+            if end.is_match(&line) {
+                in_old_region = false;
+                new_lines.extend(replacements());
+                new_lines.push(line.to_string());
+            }
+        } else if start.is_match(&line) {
+            if !replace_start {
+                new_lines.push(line.to_string());
+            }
+            in_old_region = true;
+            found = true;
+        } else {
+            new_lines.push(line.to_string());
+        }
+    }
+
+    if !found {
+        // This happens if the provided regex in `clippy_dev/src/main.rs` is not found in the
+        // given text or file. Most likely this is an error on the programmer's side and the Regex
+        // is incorrect.
+        eprintln!("error: regex `{:?}` not found. You may have to update it.", start);
+    }
+
+    FileChange {
+        changed: lines.ne(new_lines.clone()),
+        new_lines: new_lines.join("\n"),
+    }
+}
+
+#[test]
+fn test_parse_contents() {
+    let result: Vec<Lint> = parse_contents(
+        r#"
+declare_clippy_lint! {
+    pub PTR_ARG,
+    style,
+    "really long \
+     text"
+}
+
+declare_clippy_lint!{
+    pub DOC_MARKDOWN,
+    pedantic,
+    "single line"
+}
+
+/// some doc comment
+declare_deprecated_lint! {
+    pub SHOULD_ASSERT_EQ,
+    "`assert!()` will be more flexible with RFC 2011"
+}
+    "#,
+        "module_name",
+    )
+    .collect();
+
+    let expected = vec![
+        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
+        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
+        Lint::new(
+            "should_assert_eq",
+            "Deprecated",
+            "`assert!()` will be more flexible with RFC 2011",
+            Some("`assert!()` will be more flexible with RFC 2011"),
+            "module_name",
+        ),
+    ];
+    assert_eq!(expected, result);
+}
+
+#[test]
+fn test_replace_region() {
+    let text = "\nabc\n123\n789\ndef\nghi";
+    let expected = FileChange {
+        changed: true,
+        new_lines: "\nabc\nhello world\ndef\nghi".to_string(),
+    };
+    let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
+        vec!["hello world".to_string()]
+    });
+    assert_eq!(expected, result);
+}
+
+#[test]
+fn test_replace_region_with_start() {
+    let text = "\nabc\n123\n789\ndef\nghi";
+    let expected = FileChange {
+        changed: true,
+        new_lines: "\nhello world\ndef\nghi".to_string(),
+    };
+    let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
+        vec!["hello world".to_string()]
+    });
+    assert_eq!(expected, result);
+}
+
+#[test]
+fn test_replace_region_no_changes() {
+    let text = "123\n456\n789";
+    let expected = FileChange {
+        changed: false,
+        new_lines: "123\n456\n789".to_string(),
+    };
+    let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || vec![]);
+    assert_eq!(expected, result);
+}
+
+#[test]
+fn test_usable_lints() {
+    let lints = vec![
+        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
+        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"),
+        Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"),
+        Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"),
+    ];
+    let expected = vec![Lint::new(
+        "should_assert_eq2",
+        "Not Deprecated",
+        "abc",
+        None,
+        "module_name",
+    )];
+    assert_eq!(expected, Lint::usable_lints(lints.into_iter()).collect::<Vec<Lint>>());
+}
+
+#[test]
+fn test_by_lint_group() {
+    let lints = vec![
+        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
+        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
+        Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
+    ];
+    let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
+    expected.insert(
+        "group1".to_string(),
+        vec![
+            Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
+            Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
+        ],
+    );
+    expected.insert(
+        "group2".to_string(),
+        vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")],
+    );
+    assert_eq!(expected, Lint::by_lint_group(&lints));
+}
+
+#[test]
+fn test_gen_changelog_lint_list() {
+    let lints = vec![
+        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
+        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
+        Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"),
+    ];
+    let expected = vec![
+        format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
+        format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
+    ];
+    assert_eq!(expected, gen_changelog_lint_list(lints));
+}
+
+#[test]
+fn test_gen_deprecated() {
+    let lints = vec![
+        Lint::new(
+            "should_assert_eq",
+            "group1",
+            "abc",
+            Some("has been superseded by should_assert_eq2"),
+            "module_name",
+        ),
+        Lint::new(
+            "another_deprecated",
+            "group2",
+            "abc",
+            Some("will be removed"),
+            "module_name",
+        ),
+        Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
+    ];
+    let expected: Vec<String> = vec![
+        "    store.register_removed(",
+        "        \"should_assert_eq\",",
+        "        \"has been superseded by should_assert_eq2\",",
+        "    );",
+        "    store.register_removed(",
+        "        \"another_deprecated\",",
+        "        \"will be removed\",",
+        "    );",
+    ]
+    .into_iter()
+    .map(String::from)
+    .collect();
+    assert_eq!(expected, gen_deprecated(&lints));
+}
+
+#[test]
+fn test_gen_modules_list() {
+    let lints = vec![
+        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
+        Lint::new("should_assert_eq2", "group2", "abc", Some("abc"), "deprecated"),
+        Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"),
+        Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"),
+    ];
+    let expected = vec![
+        "pub mod another_module;".to_string(),
+        "pub mod module_name;".to_string(),
+    ];
+    assert_eq!(expected, gen_modules_list(lints));
+}
+
+#[test]
+fn test_gen_lint_group_list() {
+    let lints = vec![
+        Lint::new("abc", "group1", "abc", None, "module_name"),
+        Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
+        Lint::new("should_assert_eq2", "group2", "abc", Some("abc"), "deprecated"),
+        Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"),
+    ];
+    let expected = vec![
+        "        module_name::ABC,".to_string(),
+        "        module_name::SHOULD_ASSERT_EQ,".to_string(),
+    ];
+    assert_eq!(expected, gen_lint_group_list(lints));
+}
diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs
new file mode 100644 (file)
index 0000000..3f21b9d
--- /dev/null
@@ -0,0 +1,170 @@
+extern crate clap;
+extern crate clippy_dev;
+extern crate regex;
+
+use clap::{App, AppSettings, Arg, SubCommand};
+use clippy_dev::*;
+
+#[derive(PartialEq)]
+enum UpdateMode {
+    Check,
+    Change,
+}
+
+fn main() {
+    let matches = App::new("Clippy developer tooling")
+        .setting(AppSettings::SubcommandRequiredElseHelp)
+        .subcommand(
+            SubCommand::with_name("update_lints")
+                .about("Updates lint registration and information from the source code")
+                .long_about(
+                    "Makes sure that:\n \
+                     * the lint count in README.md is correct\n \
+                     * the changelog contains markdown link references at the bottom\n \
+                     * all lint groups include the correct lints\n \
+                     * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
+                     * all lints are registered in the lint store",
+                )
+                .arg(Arg::with_name("print-only").long("print-only").help(
+                    "Print a table of lints to STDOUT. \
+                     This does not include deprecated and internal lints. \
+                     (Does not modify any files)",
+                ))
+                .arg(
+                    Arg::with_name("check")
+                        .long("check")
+                        .help("Checks that util/dev update_lints has been run. Used on CI."),
+                ),
+        )
+        .get_matches();
+
+    if let Some(matches) = matches.subcommand_matches("update_lints") {
+        if matches.is_present("print-only") {
+            print_lints();
+        } else if matches.is_present("check") {
+            update_lints(&UpdateMode::Check);
+        } else {
+            update_lints(&UpdateMode::Change);
+        }
+    }
+}
+
+fn print_lints() {
+    let lint_list = gather_all();
+    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
+    let lint_count = usable_lints.len();
+    let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);
+
+    for (lint_group, mut lints) in grouped_by_lint_group {
+        if lint_group == "Deprecated" {
+            continue;
+        }
+        println!("\n## {}", lint_group);
+
+        lints.sort_by_key(|l| l.name.clone());
+
+        for lint in lints {
+            println!(
+                "* [{}]({}#{}) ({})",
+                lint.name,
+                clippy_dev::DOCS_LINK.clone(),
+                lint.name,
+                lint.desc
+            );
+        }
+    }
+
+    println!("there are {} lints", lint_count);
+}
+
+fn update_lints(update_mode: &UpdateMode) {
+    let lint_list: Vec<Lint> = gather_all().collect();
+    let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
+    let lint_count = usable_lints.len();
+
+    let mut file_change = replace_region_in_file(
+        "../README.md",
+        r#"\[There are \d+ lints included in this crate!\]\(https://rust-lang.github.io/rust-clippy/master/index.html\)"#,
+        "",
+        true,
+        update_mode == &UpdateMode::Change,
+        || {
+            vec![
+                format!("[There are {} lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)", lint_count)
+            ]
+        }
+    ).changed;
+
+    file_change |= replace_region_in_file(
+        "../CHANGELOG.md",
+        "<!-- begin autogenerated links to lint list -->",
+        "<!-- end autogenerated links to lint list -->",
+        false,
+        update_mode == &UpdateMode::Change,
+        || gen_changelog_lint_list(lint_list.clone()),
+    )
+    .changed;
+
+    file_change |= replace_region_in_file(
+        "../clippy_lints/src/lib.rs",
+        "begin deprecated lints",
+        "end deprecated lints",
+        false,
+        update_mode == &UpdateMode::Change,
+        || gen_deprecated(&lint_list),
+    )
+    .changed;
+
+    file_change |= replace_region_in_file(
+        "../clippy_lints/src/lib.rs",
+        "begin lints modules",
+        "end lints modules",
+        false,
+        update_mode == &UpdateMode::Change,
+        || gen_modules_list(lint_list.clone()),
+    )
+    .changed;
+
+    // Generate lists of lints in the clippy::all lint group
+    file_change |= replace_region_in_file(
+        "../clippy_lints/src/lib.rs",
+        r#"reg.register_lint_group\("clippy::all""#,
+        r#"\]\);"#,
+        false,
+        update_mode == &UpdateMode::Change,
+        || {
+            // clippy::all should only include the following lint groups:
+            let all_group_lints = usable_lints
+                .clone()
+                .into_iter()
+                .filter(|l| {
+                    l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
+                })
+                .collect();
+
+            gen_lint_group_list(all_group_lints)
+        },
+    )
+    .changed;
+
+    // Generate the list of lints for all other lint groups
+    for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
+        file_change |= replace_region_in_file(
+            "../clippy_lints/src/lib.rs",
+            &format!("reg.register_lint_group\\(\"clippy::{}\"", lint_group),
+            r#"\]\);"#,
+            false,
+            update_mode == &UpdateMode::Change,
+            || gen_lint_group_list(lints.clone()),
+        )
+        .changed;
+    }
+
+    if update_mode == &UpdateMode::Check && file_change {
+        println!(
+            "Not all lints defined properly. \
+             Please run `util/dev update_lints` to make sure all lints are defined properly."
+        );
+        std::process::exit(1);
+    }
+}
diff --git a/clippy_dummy/Cargo.toml b/clippy_dummy/Cargo.toml
new file mode 100644 (file)
index 0000000..f99a23d
--- /dev/null
@@ -0,0 +1,17 @@
+[package]
+name = "clippy_dummy" # rename to clippy before publishing
+version = "0.0.302"
+authors = ["Manish Goregaokar <manishsmail@gmail.com>"]
+edition = "2018"
+readme = "crates-readme.md"
+description = "A bunch of helpful lints to avoid common pitfalls in Rust."
+build = 'build.rs'
+
+repository = "https://github.com/rust-lang/rust-clippy"
+
+license = "MIT/Apache-2.0"
+keywords = ["clippy", "lint", "plugin"]
+categories = ["development-tools", "development-tools::cargo-plugins"]
+
+[build-dependencies]
+term = "0.5.1"
diff --git a/clippy_dummy/PUBLISH.md b/clippy_dummy/PUBLISH.md
new file mode 100644 (file)
index 0000000..535f11b
--- /dev/null
@@ -0,0 +1,4 @@
+This is a dummy crate to publish to crates.io. It primarily exists to ensure that folks trying to install clippy from crates.io get redirected to the `rustup` technique.
+
+Before publishing, be sure to rename `clippy_dummy` to `clippy` in `Cargo.toml`, it has a different name to avoid workspace issues.
\ No newline at end of file
diff --git a/clippy_dummy/build.rs b/clippy_dummy/build.rs
new file mode 100644 (file)
index 0000000..59d32e5
--- /dev/null
@@ -0,0 +1,42 @@
+extern crate term;
+
+fn main() {
+    if let Err(_) = foo() {
+        eprintln!("error: Clippy is no longer available via crates.io\n");
+        eprintln!("help: please run `rustup component add clippy-preview` instead");
+    }
+    std::process::exit(1);
+}
+
+fn foo() -> Result<(), ()> {
+    let mut t = term::stderr().ok_or(())?;
+
+    t.attr(term::Attr::Bold).map_err(|_| ())?;
+    t.fg(term::color::RED).map_err(|_| ())?;
+    write!(t, "\nerror: ").map_err(|_| ())?;
+
+
+    t.reset().map_err(|_| ())?;
+    t.fg(term::color::WHITE).map_err(|_| ())?;
+    writeln!(t, "Clippy is no longer available via crates.io\n").map_err(|_| ())?;
+
+
+    t.attr(term::Attr::Bold).map_err(|_| ())?;
+    t.fg(term::color::GREEN).map_err(|_| ())?;
+    write!(t, "help: ").map_err(|_| ())?;
+
+
+    t.reset().map_err(|_| ())?;
+    t.fg(term::color::WHITE).map_err(|_| ())?;
+    write!(t, "please run `").map_err(|_| ())?;
+
+    t.attr(term::Attr::Bold).map_err(|_| ())?;
+    write!(t, "rustup component add clippy-preview").map_err(|_| ())?;
+
+    t.reset().map_err(|_| ())?;
+    t.fg(term::color::WHITE).map_err(|_| ())?;
+    writeln!(t, "` instead").map_err(|_| ())?;
+
+    t.reset().map_err(|_| ())?;
+    Ok(())
+}
diff --git a/clippy_dummy/crates-readme.md b/clippy_dummy/crates-readme.md
new file mode 100644 (file)
index 0000000..4f4f499
--- /dev/null
@@ -0,0 +1,9 @@
+Installing clippy via crates.io is deprecated. Please use the following:
+
+```terminal
+rustup component add clippy-preview
+```
+
+on a Rust version 1.29 or later. You may need to run `rustup self update` if it complains about a missing clippy binary.
+
+See [the homepage](https://github.com/rust-lang/rust-clippy/#clippy) for more information
diff --git a/clippy_dummy/src/main.rs b/clippy_dummy/src/main.rs
new file mode 100644 (file)
index 0000000..a118834
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    panic!("This shouldn't even compile")
+}
index 5c3af20bde87853bae89b434ff73c083dbd0cad0..20b3a3e4937db24cb83ddb44c920dc262597ac04 100644 (file)
@@ -1,5 +1,3 @@
-cargo-features = ["edition"]
-
 [package]
 name = "clippy_lints"
 # begin automatic update
@@ -12,27 +10,27 @@ authors = [
        "Martin Carton <cartonmartin@gmail.com>"
 ]
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
-repository = "https://github.com/rust-lang-nursery/rust-clippy"
+repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
 license = "MPL-2.0"
 keywords = ["clippy", "lint", "plugin"]
 edition = "2018"
 
 [dependencies]
-cargo_metadata = "0.5"
-itertools = "0.7"
+cargo_metadata = "0.7.1"
+itertools = "0.8"
 lazy_static = "1.0.2"
 matches = "0.1.7"
 quine-mc_cluskey = "0.2.2"
 regex-syntax = "0.6"
 semver = "0.9.0"
-serde = "1.0"
-serde_derive = "1.0"
-toml = "0.4"
+serde = { version = "1.0", features = ["derive"] }
+toml = "0.5"
 unicode-normalization = "0.1"
-pulldown-cmark = "0.1"
+pulldown-cmark = "0.5.0"
 url = "1.7.0"
 if_chain = "0.1.3"
+smallvec = { version = "0.6.5", features = ["union"] }
 
 [features]
 debugging = []
index 2fa5b0ae3e417d2eaee3cf84f490af64b41bc1de..2724aa6a0523ad3050948e1475d90f8a3633ba53 100644 (file)
@@ -1,3 +1,3 @@
 This crate contains Clippy lints. For the main crate, check
 [*crates.io*](https://crates.io/crates/clippy) or
-[GitHub](https://github.com/rust-lang-nursery/rust-clippy).
+[GitHub](https://github.com/rust-lang/rust-clippy).
index cd2444ff31f0d458cba655975967b1180d7b2d89..c83172909127456e6dfc9fe37a35ee11e436859c 100644 (file)
@@ -1,77 +1,72 @@
 use crate::utils::span_lint;
+use crate::utils::sym;
+use lazy_static::lazy_static;
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use std::f64::consts as f64;
-use syntax::ast::{FloatTy, Lit, LitKind};
+use syntax::ast::{FloatTy, LitKind};
 use syntax::symbol;
+use syntax::symbol::Symbol;
 
-/// **What it does:** Checks for floating point literals that approximate
-/// constants which are defined in
-/// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
-/// or
-/// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
-/// respectively, suggesting to use the predefined constant.
-///
-/// **Why is this bad?** Usually, the definition in the standard library is more
-/// precise than what people come up with. If you find that your definition is
-/// actually more precise, please [file a Rust
-/// issue](https://github.com/rust-lang/rust/issues).
-///
-/// **Known problems:** If you happen to have a value that is within 1/8192 of a
-/// known constant, but is not *and should not* be the same, this lint will
-/// report your value anyway. We have not yet noticed any false positives in
-/// code we tested clippy with (this includes servo), but YMMV.
-///
-/// **Example:**
-/// ```rust
-/// let x = 3.14;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for floating point literals that approximate
+    /// constants which are defined in
+    /// [`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
+    /// or
+    /// [`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
+    /// respectively, suggesting to use the predefined constant.
+    ///
+    /// **Why is this bad?** Usually, the definition in the standard library is more
+    /// precise than what people come up with. If you find that your definition is
+    /// actually more precise, please [file a Rust
+    /// issue](https://github.com/rust-lang/rust/issues).
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = 3.14;
+    /// ```
     pub APPROX_CONSTANT,
     correctness,
     "the approximate of a known float constant (in `std::fXX::consts`)"
 }
 
+lazy_static! {
 // Tuples are of the form (constant, name, min_digits)
-const KNOWN_CONSTS: &[(f64, &str, usize)] = &[
-    (f64::E, "E", 4),
-    (f64::FRAC_1_PI, "FRAC_1_PI", 4),
-    (f64::FRAC_1_SQRT_2, "FRAC_1_SQRT_2", 5),
-    (f64::FRAC_2_PI, "FRAC_2_PI", 5),
-    (f64::FRAC_2_SQRT_PI, "FRAC_2_SQRT_PI", 5),
-    (f64::FRAC_PI_2, "FRAC_PI_2", 5),
-    (f64::FRAC_PI_3, "FRAC_PI_3", 5),
-    (f64::FRAC_PI_4, "FRAC_PI_4", 5),
-    (f64::FRAC_PI_6, "FRAC_PI_6", 5),
-    (f64::FRAC_PI_8, "FRAC_PI_8", 5),
-    (f64::LN_10, "LN_10", 5),
-    (f64::LN_2, "LN_2", 5),
-    (f64::LOG10_E, "LOG10_E", 5),
-    (f64::LOG2_E, "LOG2_E", 5),
-    (f64::PI, "PI", 3),
-    (f64::SQRT_2, "SQRT_2", 5),
+static ref KNOWN_CONSTS: [(f64, Symbol, usize); 16] = [
+    (f64::E, *sym::E, 4),
+    (f64::FRAC_1_PI, *sym::FRAC_1_PI, 4),
+    (f64::FRAC_1_SQRT_2, *sym::FRAC_1_SQRT_2, 5),
+    (f64::FRAC_2_PI, *sym::FRAC_2_PI, 5),
+    (f64::FRAC_2_SQRT_PI, *sym::FRAC_2_SQRT_PI, 5),
+    (f64::FRAC_PI_2, *sym::FRAC_PI_2, 5),
+    (f64::FRAC_PI_3, *sym::FRAC_PI_3, 5),
+    (f64::FRAC_PI_4, *sym::FRAC_PI_4, 5),
+    (f64::FRAC_PI_6, *sym::FRAC_PI_6, 5),
+    (f64::FRAC_PI_8, *sym::FRAC_PI_8, 5),
+    (f64::LN_10, *sym::LN_10, 5),
+    (f64::LN_2, *sym::LN_2, 5),
+    (f64::LOG10_E, *sym::LOG10_E, 5),
+    (f64::LOG2_E, *sym::LOG2_E, 5),
+    (f64::PI, *sym::PI, 3),
+    (f64::SQRT_2, *sym::SQRT_2, 5),
 ];
-
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(APPROX_CONSTANT)
-    }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+declare_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ApproxConstant {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if let ExprKind::Lit(ref lit) = e.node {
-            check_lit(cx, lit, e);
+        if let ExprKind::Lit(lit) = &e.node {
+            check_lit(cx, &lit.node, e);
         }
     }
 }
 
-fn check_lit(cx: &LateContext<'_, '_>, lit: &Lit, e: &Expr) {
-    match lit.node {
+fn check_lit(cx: &LateContext<'_, '_>, lit: &LitKind, e: &Expr) {
+    match *lit {
         LitKind::Float(s, FloatTy::F32) => check_known_consts(cx, e, s, "f32"),
         LitKind::Float(s, FloatTy::F64) => check_known_consts(cx, e, s, "f64"),
         LitKind::FloatUnsuffixed(s) => check_known_consts(cx, e, s, "f{32, 64}"),
@@ -82,7 +77,7 @@ fn check_lit(cx: &LateContext<'_, '_>, lit: &Lit, e: &Expr) {
 fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, module: &str) {
     let s = s.as_str();
     if s.parse::<f64>().is_ok() {
-        for &(constant, name, min_digits) in KNOWN_CONSTS {
+        for &(constant, name, min_digits) in KNOWN_CONSTS.iter() {
             if is_approx_const(constant, &s, min_digits) {
                 span_lint(
                     cx,
@@ -100,7 +95,7 @@ fn check_known_consts(cx: &LateContext<'_, '_>, e: &Expr, s: symbol::Symbol, mod
     }
 }
 
-/// Returns false if the number of significant figures in `value` are
+/// Returns `false` if the number of significant figures in `value` are
 /// less than `min_digits`; otherwise, returns true if `value` is equal
 /// to `constant`, rounded to the number of digits present in `value`.
 fn is_approx_const(constant: f64, value: &str, min_digits: usize) -> bool {
index b3d78d2d13f7951c3a9eb8138494b8c4dd9fd0f6..d94cd668bddc6db21adf6a29fb0bef2052ecaba3 100644 (file)
@@ -1,39 +1,40 @@
+use crate::consts::constant_simple;
 use crate::utils::span_lint;
 use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::codemap::Span;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for plain integer arithmetic.
-///
-/// **Why is this bad?** This is only checked against overflow in debug builds.
-/// In some applications one wants explicitly checked, wrapping or saturating
-/// arithmetic.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// a + 1
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for plain integer arithmetic.
+    ///
+    /// **Why is this bad?** This is only checked against overflow in debug builds.
+    /// In some applications one wants explicitly checked, wrapping or saturating
+    /// arithmetic.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// a + 1
+    /// ```
     pub INTEGER_ARITHMETIC,
     restriction,
     "any integer arithmetic statement"
 }
 
-/// **What it does:** Checks for float arithmetic.
-///
-/// **Why is this bad?** For some embedded systems or kernel development, it
-/// can be useful to rule out floating-point numbers.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// a + 1.0
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for float arithmetic.
+    ///
+    /// **Why is this bad?** For some embedded systems or kernel development, it
+    /// can be useful to rule out floating-point numbers.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// a + 1.0
+    /// ```
     pub FLOAT_ARITHMETIC,
     restriction,
     "any floating-point arithmetic statement"
 
 #[derive(Copy, Clone, Default)]
 pub struct Arithmetic {
-    span: Option<Span>,
+    expr_span: Option<Span>,
+    /// This field is used to check whether expressions are constants, such as in enum discriminants
+    /// and consts
+    const_span: Option<Span>,
 }
 
-impl LintPass for Arithmetic {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INTEGER_ARITHMETIC, FLOAT_ARITHMETIC)
-    }
-}
+impl_lint_pass!(Arithmetic => [INTEGER_ARITHMETIC, FLOAT_ARITHMETIC]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        if self.span.is_some() {
+        if self.expr_span.is_some() {
             return;
         }
-        match expr.node {
-            hir::ExprKind::Binary(ref op, ref l, ref r) => {
+
+        if let Some(span) = self.const_span {
+            if span.contains(expr.span) {
+                return;
+            }
+        }
+        match &expr.node {
+            hir::ExprKind::Binary(op, l, r) => {
                 match op.node {
                     hir::BinOpKind::And
                     | hir::BinOpKind::Or
@@ -76,20 +82,22 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                 let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r));
                 if l_ty.is_integral() && r_ty.is_integral() {
                     span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                    self.span = Some(expr.span);
+                    self.expr_span = Some(expr.span);
                 } else if l_ty.is_floating_point() && r_ty.is_floating_point() {
                     span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
-                    self.span = Some(expr.span);
+                    self.expr_span = Some(expr.span);
                 }
             },
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
+            hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => {
                 let ty = cx.tables.expr_ty(arg);
                 if ty.is_integral() {
-                    span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                    self.span = Some(expr.span);
+                    if constant_simple(cx, cx.tables, expr).is_none() {
+                        span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                        self.expr_span = Some(expr.span);
+                    }
                 } else if ty.is_floating_point() {
                     span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
-                    self.span = Some(expr.span);
+                    self.expr_span = Some(expr.span);
                 }
             },
             _ => (),
@@ -97,8 +105,38 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
     }
 
     fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        if Some(expr.span) == self.span {
-            self.span = None;
+        if Some(expr.span) == self.expr_span {
+            self.expr_span = None;
+        }
+    }
+
+    fn check_body(&mut self, cx: &LateContext<'_, '_>, body: &hir::Body) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+
+        match cx.tcx.hir().body_owner_kind(body_owner) {
+            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
+                let body_span = cx.tcx.hir().span(body_owner);
+
+                if let Some(span) = self.const_span {
+                    if span.contains(body_span) {
+                        return;
+                    }
+                }
+                self.const_span = Some(body_span);
+            },
+            hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (),
+        }
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'_, '_>, body: &hir::Body) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_span = cx.tcx.hir().span(body_owner);
+
+        if let Some(span) = self.const_span {
+            if span.contains(body_span) {
+                return;
+            }
         }
+        self.const_span = None;
     }
 }
diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs
new file mode 100644 (file)
index 0000000..1690c10
--- /dev/null
@@ -0,0 +1,75 @@
+use if_chain::if_chain;
+use rustc::hir::{Expr, ExprKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax_pos::Span;
+
+use crate::consts::{constant, Constant};
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, is_direct_expn_of, span_help_and_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `assert!(true)` and `assert!(false)` calls.
+    ///
+    /// **Why is this bad?** Will be optimized out by the compiler or should probably be replaced by a
+    /// panic!() or unreachable!()
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// assert!(false)
+    /// // or
+    /// assert!(true)
+    /// // or
+    /// const B: bool = false;
+    /// assert!(B)
+    /// ```
+    pub ASSERTIONS_ON_CONSTANTS,
+    style,
+    "`assert!(true)` / `assert!(false)` will be optimized out by the compiler, and should probably be replaced by a `panic!()` or `unreachable!()`"
+}
+
+declare_lint_pass!(AssertionsOnConstants => [ASSERTIONS_ON_CONSTANTS]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssertionsOnConstants {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
+        let mut is_debug_assert = false;
+        let debug_assert_not_in_macro_or_desugar = |span: Span| {
+            is_debug_assert = true;
+            // Check that `debug_assert!` itself is not inside a macro
+            !in_macro_or_desugar(span)
+        };
+        if_chain! {
+            if let Some(assert_span) = is_direct_expn_of(e.span, *sym::assert);
+            if !in_macro_or_desugar(assert_span)
+                || is_direct_expn_of(assert_span, *sym::debug_assert)
+                    .map_or(false, debug_assert_not_in_macro_or_desugar);
+            if let ExprKind::Unary(_, ref lit) = e.node;
+            if let Some(bool_const) = constant(cx, cx.tables, lit);
+            then {
+                match bool_const.0 {
+                    Constant::Bool(true) => {
+                        span_help_and_lint(
+                            cx,
+                            ASSERTIONS_ON_CONSTANTS,
+                            e.span,
+                            "`assert!(true)` will be optimized out by the compiler",
+                            "remove it"
+                        );
+                    },
+                    Constant::Bool(false) if !is_debug_assert => {
+                        span_help_and_lint(
+                            cx,
+                            ASSERTIONS_ON_CONSTANTS,
+                            e.span,
+                            "`assert!(false)` should probably be replaced",
+                            "use `panic!()` or `unreachable!()`"
+                        );
+                    },
+                    _ => (),
+                }
+            }
+        }
+    }
+}
index 1ce690abcfe95d87dd2cd7a3fc1ed964097f0d2b..ff34cb3d998a9e8dcc89cdec1a87283c13666787 100644 (file)
-use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
-use crate::utils::{higher, sugg};
+use if_chain::if_chain;
 use rustc::hir;
 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use syntax::ast;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for compound assignment operations (`+=` and
-/// similar).
-///
-/// **Why is this bad?** Projects with many developers from languages without
-/// those operations may find them unreadable and not worth their weight.
-///
-/// **Known problems:** Types implementing `OpAssign` don't necessarily
-/// implement `Op`.
-///
-/// **Example:**
-/// ```rust
-/// a += 1;
-/// ```
-declare_clippy_lint! {
-    pub ASSIGN_OPS,
-    restriction,
-    "any compound assignment operation"
-}
+use crate::utils::{
+    get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, trait_ref_of_method, SpanlessEq,
+};
+use crate::utils::{higher, sugg};
+use syntax::symbol::Symbol;
 
-/// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
-/// patterns.
-///
-/// **Why is this bad?** These can be written as the shorter `a op= b`.
-///
-/// **Known problems:** While forbidden by the spec, `OpAssign` traits may have
-/// implementations that differ from the regular `Op` impl.
-///
-/// **Example:**
-/// ```rust
-/// let mut a = 5;
-/// ...
-/// a = a + b;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
+    /// patterns.
+    ///
+    /// **Why is this bad?** These can be written as the shorter `a op= b`.
+    ///
+    /// **Known problems:** While forbidden by the spec, `OpAssign` traits may have
+    /// implementations that differ from the regular `Op` impl.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut a = 5;
+    /// let b = 0;
+    /// // ...
+    /// a = a + b;
+    /// ```
     pub ASSIGN_OP_PATTERN,
     style,
     "assigning the result of an operation on a variable to that same variable"
 }
 
-/// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns.
-///
-/// **Why is this bad?** Most likely these are bugs where one meant to write `a
-/// op= b`.
-///
-/// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have
-/// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore it suggests both.
-/// If `a op= a op b` is really the correct behaviour it should be
-/// written as `a = a op a op b` as it's less confusing.
-///
-/// **Example:**
-/// ```rust
-/// let mut a = 5;
-/// ...
-/// a += a + b;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `a op= a op b` or `a op= b op a` patterns.
+    ///
+    /// **Why is this bad?** Most likely these are bugs where one meant to write `a
+    /// op= b`.
+    ///
+    /// **Known problems:** Clippy cannot know for sure if `a op= a op b` should have
+    /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
+    /// If `a op= a op b` is really the correct behaviour it should be
+    /// written as `a = a op a op b` as it's less confusing.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut a = 5;
+    /// ...
+    /// a += a + b;
+    /// ```
     pub MISREFACTORED_ASSIGN_OP,
     complexity,
     "having a variable on both sides of an assign op"
 }
 
-#[derive(Copy, Clone, Default)]
-pub struct AssignOps;
-
-impl LintPass for AssignOps {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ASSIGN_OPS, ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP)
-    }
-}
+declare_lint_pass!(AssignOps => [ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
+    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        match expr.node {
-            hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                span_lint_and_then(cx, ASSIGN_OPS, expr.span, "assign operation detected", |db| {
-                    let lhs = &sugg::Sugg::hir(cx, lhs, "..");
-                    let rhs = &sugg::Sugg::hir(cx, rhs, "..");
-
-                    db.span_suggestion(
-                        expr.span,
-                        "replace it with",
-                        format!("{} = {}", lhs, sugg::make_binop(higher::binop(op.node), lhs, rhs)),
-                    );
-                });
-                if let hir::ExprKind::Binary(binop, ref l, ref r) = rhs.node {
-                    if op.node == binop.node {
-                        let lint = |assignee: &hir::Expr, rhs_other: &hir::Expr| {
-                            span_lint_and_then(
-                                cx,
-                                MISREFACTORED_ASSIGN_OP,
-                                expr.span,
-                                "variable appears on both sides of an assignment operation",
-                                |db| {
-                                    if let (Some(snip_a), Some(snip_r)) =
-                                        (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span))
-                                    {
-                                        let a = &sugg::Sugg::hir(cx, assignee, "..");
-                                        let r = &sugg::Sugg::hir(cx, rhs, "..");
-                                        let long =
-                                            format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r));
-                                        db.span_suggestion(
-                                            expr.span,
-                                            &format!(
-                                                "Did you mean {} = {} {} {} or {}? Consider replacing it with",
-                                                snip_a,
-                                                snip_a,
-                                                op.node.as_str(),
-                                                snip_r,
-                                                long
-                                            ),
-                                            format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
-                                        );
-                                        db.span_suggestion(expr.span, "or", long);
-                                    }
-                                },
-                            );
-                        };
-                        // lhs op= l op r
-                        if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
-                            lint(lhs, r);
-                        }
-                        // lhs op= l commutative_op r
-                        if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) {
-                            lint(lhs, l);
-                        }
+        match &expr.node {
+            hir::ExprKind::AssignOp(op, lhs, rhs) => {
+                if let hir::ExprKind::Binary(binop, l, r) = &rhs.node {
+                    if op.node != binop.node {
+                        return;
+                    }
+                    // lhs op= l op r
+                    if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, l) {
+                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, r);
+                    }
+                    // lhs op= l commutative_op r
+                    if is_commutative(op.node) && SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, r) {
+                        lint_misrefactored_assign_op(cx, expr, *op, rhs, lhs, l);
                     }
                 }
             },
-            hir::ExprKind::Assign(ref assignee, ref e) => {
-                if let hir::ExprKind::Binary(op, ref l, ref r) = e.node {
-                    #[allow(cyclomatic_complexity)]
+            hir::ExprKind::Assign(assignee, e) => {
+                if let hir::ExprKind::Binary(op, l, r) = &e.node {
+                    #[allow(clippy::cognitive_complexity)]
                     let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
                         let ty = cx.tables.expr_ty(assignee);
                         let rty = cx.tables.expr_ty(rhs);
@@ -149,23 +89,21 @@ macro_rules! ops {
                              $($trait_name:ident),+) => {
                                 match $op {
                                     $(hir::BinOpKind::$trait_name => {
-                                        let [krate, module] = crate::utils::paths::OPS_MODULE;
-                                        let path = [krate, module, concat!(stringify!($trait_name), "Assign")];
+                                        let [krate, module] = *crate::utils::paths::OPS_MODULE;
+                                        let ident = {
+                                            *crate::utils::sym::assign::$trait_name
+                                        };
+                                        let path: [Symbol; 3] = [krate, module, ident];
                                         let trait_id = if let Some(trait_id) = get_trait_def_id($cx, &path) {
                                             trait_id
                                         } else {
                                             return; // useless if the trait doesn't exist
                                         };
                                         // check that we are not inside an `impl AssignOp` of this exact operation
-                                        let parent_fn = cx.tcx.hir.get_parent(e.id);
-                                        let parent_impl = cx.tcx.hir.get_parent(parent_fn);
-                                        // the crate node is the only one that is not in the map
+                                        let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id);
                                         if_chain! {
-                                            if parent_impl != ast::CRATE_NODE_ID;
-                                            if let hir::map::Node::NodeItem(item) = cx.tcx.hir.get(parent_impl);
-                                            if let hir::ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) =
-                                                item.node;
-                                            if trait_ref.path.def.def_id() == trait_id;
+                                            if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
+                                            if trait_ref.path.res.def_id() == trait_id;
                                             then { return; }
                                         }
                                         implements_trait($cx, $ty, trait_id, &[$rty])
@@ -205,6 +143,7 @@ macro_rules! ops {
                                             expr.span,
                                             "replace it with",
                                             format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
+                                            Applicability::MachineApplicable,
                                         );
                                     }
                                 },
@@ -226,7 +165,10 @@ macro_rules! ops {
                             lint(assignee, r);
                         }
                         // a = b commutative_op a
-                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) {
+                        // Limited to primitive type as these ops are know to be commutative
+                        if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
+                            && cx.tables.expr_ty(assignee).is_primitive_ty()
+                        {
                             match op.node {
                                 hir::BinOpKind::Add
                                 | hir::BinOpKind::Mul
@@ -248,6 +190,48 @@ macro_rules! ops {
     }
 }
 
+fn lint_misrefactored_assign_op(
+    cx: &LateContext<'_, '_>,
+    expr: &hir::Expr,
+    op: hir::BinOp,
+    rhs: &hir::Expr,
+    assignee: &hir::Expr,
+    rhs_other: &hir::Expr,
+) {
+    span_lint_and_then(
+        cx,
+        MISREFACTORED_ASSIGN_OP,
+        expr.span,
+        "variable appears on both sides of an assignment operation",
+        |db| {
+            if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) {
+                let a = &sugg::Sugg::hir(cx, assignee, "..");
+                let r = &sugg::Sugg::hir(cx, rhs, "..");
+                let long = format!("{} = {}", snip_a, sugg::make_binop(higher::binop(op.node), a, r));
+                db.span_suggestion(
+                    expr.span,
+                    &format!(
+                        "Did you mean {} = {} {} {} or {}? Consider replacing it with",
+                        snip_a,
+                        snip_a,
+                        op.node.as_str(),
+                        snip_r,
+                        long
+                    ),
+                    format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
+                    Applicability::MachineApplicable,
+                );
+                db.span_suggestion(
+                    expr.span,
+                    "or",
+                    long,
+                    Applicability::MachineApplicable, // snippet
+                );
+            }
+        },
+    );
+}
+
 fn is_commutative(op: hir::BinOpKind) -> bool {
     use rustc::hir::BinOpKind::*;
     match op {
index 3d25f524afd87fabcc9e37097b3d731c203d6cdb..754dc3a06ae7b98e25e0cf3d346270478f635adb 100644 (file)
 //! checks for attributes
 
 use crate::reexport::*;
+use crate::utils::sym;
 use crate::utils::{
-    in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then,
-    without_block_comments,
+    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,
 };
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
-use rustc::ty::{self, TyCtxt};
+use rustc::hir::*;
+use rustc::lint::{
+    in_external_macro, CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray,
+    LintContext, LintPass,
+};
+use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use semver::Version;
-use syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
-use syntax::codemap::Span;
+use syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
+use syntax::source_map::Span;
+use syntax::symbol::Symbol;
 
-/// **What it does:** Checks for items annotated with `#[inline(always)]`,
-/// unless the annotated function is empty or simply panics.
-///
-/// **Why is this bad?** While there are valid uses of this annotation (and once
-/// you know when to use it, by all means `allow` this lint), it's a common
-/// newbie-mistake to pepper one's code with it.
-///
-/// As a rule of thumb, before slapping `#[inline(always)]` on a function,
-/// measure if that additional function call really affects your runtime profile
-/// sufficiently to make up for the increase in compile time.
-///
-/// **Known problems:** False positives, big time. This lint is meant to be
-/// deactivated by everyone doing serious performance work. This means having
-/// done the measurement.
-///
-/// **Example:**
-/// ```rust
-/// #[inline(always)]
-/// fn not_quite_hot_code(..) { ... }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for items annotated with `#[inline(always)]`,
+    /// unless the annotated function is empty or simply panics.
+    ///
+    /// **Why is this bad?** While there are valid uses of this annotation (and once
+    /// you know when to use it, by all means `allow` this lint), it's a common
+    /// newbie-mistake to pepper one's code with it.
+    ///
+    /// As a rule of thumb, before slapping `#[inline(always)]` on a function,
+    /// measure if that additional function call really affects your runtime profile
+    /// sufficiently to make up for the increase in compile time.
+    ///
+    /// **Known problems:** False positives, big time. This lint is meant to be
+    /// deactivated by everyone doing serious performance work. This means having
+    /// done the measurement.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// #[inline(always)]
+    /// fn not_quite_hot_code(..) { ... }
+    /// ```
     pub INLINE_ALWAYS,
     pedantic,
     "use of `#[inline(always)]`"
 }
 
-/// **What it does:** Checks for `extern crate` and `use` items annotated with
-/// lint attributes.
-///
-/// This lint whitelists `#[allow(unused_imports)]` and `#[allow(deprecated)]` on
-/// `use` items and `#[allow(unused_imports)]` on `extern crate` items with a
-/// `#[macro_use]` attribute.
-///
-/// **Why is this bad?** Lint attributes have no effect on crate imports. Most
-/// likely a `!` was forgotten.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// // Bad
-/// #[deny(dead_code)]
-/// extern crate foo;
-/// #[forbid(dead_code)]
-/// use foo::bar;
-///
-/// // Ok
-/// #[allow(unused_imports)]
-/// use foo::baz;
-/// #[allow(unused_imports)]
-/// #[macro_use]
-/// extern crate baz;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `extern crate` and `use` items annotated with
+    /// lint attributes.
+    ///
+    /// This lint whitelists `#[allow(unused_imports)]` and `#[allow(deprecated)]` on
+    /// `use` items and `#[allow(unused_imports)]` on `extern crate` items with a
+    /// `#[macro_use]` attribute.
+    ///
+    /// **Why is this bad?** Lint attributes have no effect on crate imports. Most
+    /// likely a `!` was forgotten.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// // Bad
+    /// #[deny(dead_code)]
+    /// extern crate foo;
+    /// #[forbid(dead_code)]
+    /// use foo::bar;
+    ///
+    /// // Ok
+    /// #[allow(unused_imports)]
+    /// use foo::baz;
+    /// #[allow(unused_imports)]
+    /// #[macro_use]
+    /// extern crate baz;
+    /// ```
     pub USELESS_ATTRIBUTE,
     correctness,
     "use of lint attributes on `extern crate` items"
 }
 
-/// **What it does:** Checks for `#[deprecated]` annotations with a `since`
-/// field that is not a valid semantic version.
-///
-/// **Why is this bad?** For checking the version of the deprecation, it must be
-/// a valid semver. Failing that, the contained information is useless.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// #[deprecated(since = "forever")]
-/// fn something_else(..) { ... }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `#[deprecated]` annotations with a `since`
+    /// field that is not a valid semantic version.
+    ///
+    /// **Why is this bad?** For checking the version of the deprecation, it must be
+    /// a valid semver. Failing that, the contained information is useless.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// #[deprecated(since = "forever")]
+    /// fn something_else() { /* ... */ }
+    /// ```
     pub DEPRECATED_SEMVER,
     correctness,
     "use of `#[deprecated(since = \"x\")]` where x is not semver"
 }
 
-/// **What it does:** Checks for empty lines after outer attributes
-///
-/// **Why is this bad?**
-/// Most likely the attribute was meant to be an inner attribute using a '!'.
-/// If it was meant to be an outer attribute, then the following item
-/// should not be separated by empty lines.
-///
-/// **Known problems:** Can cause false positives.
-///
-/// From the clippy side it's difficult to detect empty lines between an attributes and the
-/// following item because empty lines and comments are not part of the AST. The parsing
-/// currently works for basic cases but is not perfect.
-///
-/// **Example:**
-/// ```rust
-/// // Bad
-/// #[inline(always)]
-///
-/// fn not_quite_good_code(..) { ... }
-///
-/// // Good (as inner attribute)
-/// #![inline(always)]
-///
-/// fn this_is_fine(..) { ... }
-///
-/// // Good (as outer attribute)
-/// #[inline(always)]
-/// fn this_is_fine_too(..) { ... }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for empty lines after outer attributes
+    ///
+    /// **Why is this bad?**
+    /// Most likely the attribute was meant to be an inner attribute using a '!'.
+    /// If it was meant to be an outer attribute, then the following item
+    /// should not be separated by empty lines.
+    ///
+    /// **Known problems:** Can cause false positives.
+    ///
+    /// From the clippy side it's difficult to detect empty lines between an attributes and the
+    /// following item because empty lines and comments are not part of the AST. The parsing
+    /// currently works for basic cases but is not perfect.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// #[inline(always)]
+    ///
+    /// fn not_quite_good_code(..) { ... }
+    ///
+    /// // Good (as inner attribute)
+    /// #![inline(always)]
+    ///
+    /// fn this_is_fine(..) { ... }
+    ///
+    /// // Good (as outer attribute)
+    /// #[inline(always)]
+    /// fn this_is_fine_too(..) { ... }
+    /// ```
     pub EMPTY_LINE_AFTER_OUTER_ATTR,
     nursery,
     "empty line after outer attribute"
 }
 
-#[derive(Copy, Clone)]
-pub struct AttrPass;
+declare_clippy_lint! {
+    /// **What it does:** Checks for `allow`/`warn`/`deny`/`forbid` attributes with scoped clippy
+    /// lints and if those lints exist in clippy. If there is a uppercase letter in the lint name
+    /// (not the tool name) and a lowercase version of this lint exists, it will suggest to lowercase
+    /// the lint name.
+    ///
+    /// **Why is this bad?** A lint attribute with a mistyped lint name won't have an effect.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust
+    /// #![warn(if_not_els)]
+    /// #![deny(clippy::All)]
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// #![warn(if_not_else)]
+    /// #![deny(clippy::all)]
+    /// ```
+    pub UNKNOWN_CLIPPY_LINTS,
+    style,
+    "unknown_lints for scoped Clippy lints"
+}
 
-impl LintPass for AttrPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            INLINE_ALWAYS,
-            DEPRECATED_SEMVER,
-            USELESS_ATTRIBUTE,
-            EMPTY_LINE_AFTER_OUTER_ATTR
-        )
-    }
+declare_clippy_lint! {
+    /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
+    /// with `#[rustfmt::skip]`.
+    ///
+    /// **Why is this bad?** Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
+    /// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
+    ///
+    /// **Known problems:** This lint doesn't detect crate level inner attributes, because they get
+    /// processed before the PreExpansionPass lints get executed. See
+    /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
+    ///
+    /// **Example:**
+    ///
+    /// Bad:
+    /// ```rust
+    /// #[cfg_attr(rustfmt, rustfmt_skip)]
+    /// fn main() { }
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// #[rustfmt::skip]
+    /// fn main() { }
+    /// ```
+    pub DEPRECATED_CFG_ATTR,
+    complexity,
+    "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`"
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
+declare_lint_pass!(Attributes => [
+    INLINE_ALWAYS,
+    DEPRECATED_SEMVER,
+    USELESS_ATTRIBUTE,
+    EMPTY_LINE_AFTER_OUTER_ATTR,
+    UNKNOWN_CLIPPY_LINTS,
+]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Attributes {
     fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute) {
-        if let Some(ref items) = attr.meta_item_list() {
-            if items.is_empty() || attr.name() != "deprecated" {
-                return;
-            }
-            for item in items {
-                if_chain! {
-                    if let NestedMetaItemKind::MetaItem(ref mi) = item.node;
-                    if let MetaItemKind::NameValue(ref lit) = mi.node;
-                    if mi.name() == "since";
-                    then {
-                        check_semver(cx, item.span, lit);
+        if let Some(items) = &attr.meta_item_list() {
+            if let Some(ident) = attr.ident() {
+                match &*ident.as_str() {
+                    "allow" | "warn" | "deny" | "forbid" => {
+                        check_clippy_lint_names(cx, items);
+                    },
+                    _ => {},
+                }
+                if items.is_empty() || !attr.check_name(*sym::deprecated) {
+                    return;
+                }
+                for item in items {
+                    if_chain! {
+                        if let NestedMetaItem::MetaItem(mi) = &item;
+                        if let MetaItemKind::NameValue(lit) = &mi.node;
+                        if mi.check_name(*sym::since);
+                        then {
+                            check_semver(cx, item.span(), lit);
+                        }
                     }
                 }
             }
@@ -161,50 +225,67 @@ fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute)
     }
 
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
-        if is_relevant_item(cx.tcx, item) {
-            check_attrs(cx, item.span, item.name, &item.attrs)
+        if is_relevant_item(cx, item) {
+            check_attrs(cx, item.span, item.ident.name, &item.attrs)
         }
         match item.node {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
-                let skip_unused_imports = item.attrs.iter().any(|attr| attr.name() == "macro_use");
+                let skip_unused_imports = item.attrs.iter().any(|attr| attr.check_name(*sym::macro_use));
 
                 for attr in &item.attrs {
-                    if let Some(ref lint_list) = attr.meta_item_list() {
-                        match &*attr.name().as_str() {
-                            "allow" | "warn" | "deny" | "forbid" => {
-                                // whitelist `unused_imports` and `deprecated` for `use` items
-                                // and `unused_imports` for `extern crate` items with `macro_use`
-                                for lint in lint_list {
-                                    match item.node {
-                                        ItemKind::Use(..) => if is_word(lint, "unused_imports")
-                                                                || is_word(lint, "deprecated") {
-                                                return
-                                        },
-                                        ItemKind::ExternCrate(..) => if is_word(lint, "unused_imports")
-                                                                        && skip_unused_imports {
-                                                return
-                                        },
-                                        _ => {},
+                    if in_external_macro(cx.sess(), attr.span) {
+                        return;
+                    }
+                    if let Some(lint_list) = &attr.meta_item_list() {
+                        if let Some(ident) = attr.ident() {
+                            match &*ident.as_str() {
+                                "allow" | "warn" | "deny" | "forbid" => {
+                                    // whitelist `unused_imports` and `deprecated` for `use` items
+                                    // and `unused_imports` for `extern crate` items with `macro_use`
+                                    for lint in lint_list {
+                                        match item.node {
+                                            ItemKind::Use(..) => {
+                                                if is_word(lint, *sym::unused_imports)
+                                                    || is_word(lint, *sym::deprecated)
+                                                {
+                                                    return;
+                                                }
+                                            },
+                                            ItemKind::ExternCrate(..) => {
+                                                if is_word(lint, *sym::unused_imports) && skip_unused_imports {
+                                                    return;
+                                                }
+                                                if is_word(lint, *sym::unused_extern_crates) {
+                                                    return;
+                                                }
+                                            },
+                                            _ => {},
+                                        }
                                     }
-                                }
-                                let line_span = last_line_of_span(cx, attr.span);
+                                    let line_span = last_line_of_span(cx, attr.span);
 
-                                if let Some(mut sugg) = snippet_opt(cx, line_span) {
-                                    if sugg.contains("#[") {
-                                        span_lint_and_then(
-                                            cx,
-                                            USELESS_ATTRIBUTE,
-                                            line_span,
-                                            "useless lint attribute",
-                                            |db| {
-                                                sugg = sugg.replacen("#[", "#![", 1);
-                                                db.span_suggestion(line_span, "if you just forgot a `!`, use", sugg);
-                                            },
-                                        );
+                                    if let Some(mut sugg) = snippet_opt(cx, line_span) {
+                                        if sugg.contains("#[") {
+                                            span_lint_and_then(
+                                                cx,
+                                                USELESS_ATTRIBUTE,
+                                                line_span,
+                                                "useless lint attribute",
+                                                |db| {
+                                                    sugg = sugg.replacen("#[", "#![", 1);
+                                                    db.span_suggestion(
+                                                        line_span,
+                                                        "if you just forgot a `!`, use",
+                                                        sugg,
+                                                        Applicability::MachineApplicable,
+                                                    );
+                                                },
+                                            );
+                                        }
                                     }
-                                }
-                            },
-                            _ => {},
+                                },
+                                _ => {},
+                            }
                         }
                     }
                 }
@@ -214,74 +295,124 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
-        if is_relevant_impl(cx.tcx, item) {
+        if is_relevant_impl(cx, item) {
             check_attrs(cx, item.span, item.ident.name, &item.attrs)
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
-        if is_relevant_trait(cx.tcx, item) {
+        if is_relevant_trait(cx, item) {
             check_attrs(cx, item.span, item.ident.name, &item.attrs)
         }
     }
 }
 
-fn is_relevant_item(tcx: TyCtxt<'_, '_, '_>, item: &Item) -> bool {
+#[allow(clippy::single_match_else)]
+fn check_clippy_lint_names(cx: &LateContext<'_, '_>, items: &[NestedMetaItem]) {
+    let lint_store = cx.lints();
+    for lint in items {
+        if_chain! {
+            if let Some(meta_item) = lint.meta_item();
+            if meta_item.path.segments.len() > 1;
+            if let tool_name = meta_item.path.segments[0].ident;
+            if tool_name.as_str() == "clippy";
+            let name = meta_item.path.segments.last().unwrap().ident.name;
+            if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(
+                &name.as_str(),
+                Some(tool_name.as_str()),
+            );
+            then {
+                span_lint_and_then(
+                    cx,
+                    UNKNOWN_CLIPPY_LINTS,
+                    lint.span(),
+                    &format!("unknown clippy lint: clippy::{}", name),
+                    |db| {
+                        if name.as_str().chars().any(char::is_uppercase) {
+                            let name_lower = name.as_str().to_lowercase();
+                            match lint_store.check_lint_name(
+                                &name_lower,
+                                Some(tool_name.as_str())
+                            ) {
+                                // FIXME: can we suggest similar lint names here?
+                                // https://github.com/rust-lang/rust/pull/56992
+                                CheckLintNameResult::NoLint(None) => (),
+                                _ => {
+                                    db.span_suggestion(
+                                        lint.span(),
+                                        "lowercase the lint name",
+                                        name_lower,
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                }
+                            }
+                        }
+                    }
+                );
+            }
+        };
+    }
+}
+
+fn is_relevant_item(cx: &LateContext<'_, '_>, item: &Item) -> bool {
     if let ItemKind::Fn(_, _, _, eid) = item.node {
-        is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
+        is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value)
     } else {
         true
     }
 }
 
-fn is_relevant_impl(tcx: TyCtxt<'_, '_, '_>, item: &ImplItem) -> bool {
+fn is_relevant_impl(cx: &LateContext<'_, '_>, item: &ImplItem) -> bool {
     match item.node {
-        ImplItemKind::Method(_, eid) => is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value),
+        ImplItemKind::Method(_, eid) => is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value),
         _ => false,
     }
 }
 
-fn is_relevant_trait(tcx: TyCtxt<'_, '_, '_>, item: &TraitItem) -> bool {
+fn is_relevant_trait(cx: &LateContext<'_, '_>, item: &TraitItem) -> bool {
     match item.node {
         TraitItemKind::Method(_, TraitMethod::Required(_)) => true,
         TraitItemKind::Method(_, TraitMethod::Provided(eid)) => {
-            is_relevant_expr(tcx, tcx.body_tables(eid), &tcx.hir.body(eid).value)
+            is_relevant_expr(cx, cx.tcx.body_tables(eid), &cx.tcx.hir().body(eid).value)
         },
         _ => false,
     }
 }
 
-fn is_relevant_block(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, block: &Block) -> bool {
+fn is_relevant_block(cx: &LateContext<'_, '_>, tables: &ty::TypeckTables<'_>, block: &Block) -> bool {
     if let Some(stmt) = block.stmts.first() {
-        match stmt.node {
-            StmtKind::Decl(_, _) => true,
-            StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => is_relevant_expr(tcx, tables, expr),
+        match &stmt.node {
+            StmtKind::Local(_) => true,
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, tables, expr),
+            _ => false,
         }
     } else {
-        block.expr.as_ref().map_or(false, |e| is_relevant_expr(tcx, tables, e))
+        block.expr.as_ref().map_or(false, |e| is_relevant_expr(cx, tables, e))
     }
 }
 
-fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr: &Expr) -> bool {
-    match expr.node {
-        ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block),
-        ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e),
+fn is_relevant_expr(cx: &LateContext<'_, '_>, tables: &ty::TypeckTables<'_>, expr: &Expr) -> bool {
+    match &expr.node {
+        ExprKind::Block(block, _) => is_relevant_block(cx, tables, block),
+        ExprKind::Ret(Some(e)) => is_relevant_expr(cx, tables, e),
         ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
-        ExprKind::Call(ref path_expr, _) => if let ExprKind::Path(ref qpath) = path_expr.node {
-            if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
-                !match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
+        ExprKind::Call(path_expr, _) => {
+            if let ExprKind::Path(qpath) = &path_expr.node {
+                if let Some(fun_id) = tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
+                    !match_def_path(cx, fun_id, &*paths::BEGIN_PANIC)
+                } else {
+                    true
+                }
             } else {
                 true
             }
-        } else {
-            true
         },
         _ => true,
     }
 }
 
 fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attribute]) {
-    if in_macro(span) {
+    if in_macro_or_desugar(span) {
         return;
     }
 
@@ -306,17 +437,18 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
                         cx,
                         EMPTY_LINE_AFTER_OUTER_ATTR,
                         begin_of_attr_to_item,
-                        "Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?"
+                        "Found an empty line after an outer attribute. \
+                         Perhaps you forgot to add a '!' to make it an inner attribute?",
                     );
                 }
             }
         }
 
-        if let Some(ref values) = attr.meta_item_list() {
-            if values.len() != 1 || attr.name() != "inline" {
+        if let Some(values) = attr.meta_item_list() {
+            if values.len() != 1 || !attr.check_name(*sym::inline) {
                 continue;
             }
-            if is_word(&values[0], "always") {
+            if is_word(&values[0], *sym::always) {
                 span_lint(
                     cx,
                     INLINE_ALWAYS,
@@ -332,7 +464,7 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
 }
 
 fn check_semver(cx: &LateContext<'_, '_>, span: Span, lit: &Lit) {
-    if let LitKind::Str(ref is, _) = lit.node {
+    if let LitKind::Str(is, _) = lit.node {
         if Version::parse(&is.as_str()).is_ok() {
             return;
         }
@@ -345,24 +477,44 @@ fn check_semver(cx: &LateContext<'_, '_>, span: Span, lit: &Lit) {
     );
 }
 
-fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool {
-    if let NestedMetaItemKind::MetaItem(ref mi) = nmi.node {
-        mi.is_word() && mi.name() == expected
+fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
+    if let NestedMetaItem::MetaItem(mi) = &nmi {
+        mi.is_word() && mi.check_name(expected)
     } else {
         false
     }
 }
 
-// If the snippet is empty, it's an attribute that was inserted during macro
-// expansion and we want to ignore those, because they could come from external
-// sources that the user has no control over.
-// For some reason these attributes don't have any expansion info on them, so
-// we have to check it this way until there is a better way.
-fn is_present_in_source(cx: &LateContext<'_, '_>, span: Span) -> bool {
-    if let Some(snippet) = snippet_opt(cx, span) {
-        if snippet.is_empty() {
-            return false;
+declare_lint_pass!(DeprecatedCfgAttribute => [DEPRECATED_CFG_ATTR]);
+
+impl EarlyLintPass for DeprecatedCfgAttribute {
+    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
+        if_chain! {
+            // check cfg_attr
+            if attr.check_name(*sym::cfg_attr);
+            if let Some(items) = attr.meta_item_list();
+            if items.len() == 2;
+            // check for `rustfmt`
+            if let Some(feature_item) = items[0].meta_item();
+            if feature_item.check_name(*sym::rustfmt);
+            // check for `rustfmt_skip` and `rustfmt::skip`
+            if let Some(skip_item) = &items[1].meta_item();
+            if skip_item.check_name(*sym::rustfmt_skip) ||
+                skip_item.path.segments.last().expect("empty path in attribute").ident.name == *sym::skip;
+            // Only lint outer attributes, because custom inner attributes are unstable
+            // Tracking issue: https://github.com/rust-lang/rust/issues/54726
+            if let AttrStyle::Outer = attr.style;
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    DEPRECATED_CFG_ATTR,
+                    attr.span,
+                    "`cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes",
+                    "use",
+                    "#[rustfmt::skip]".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
         }
     }
-    true
 }
index 249ebbde2f79fcd1ffa8717fb77c4d88017ccbee..71075500528e1030b8b898f0f676dec87ab9b351 100644 (file)
@@ -1,90 +1,94 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::consts::{constant, Constant};
+use crate::utils::sugg::Sugg;
+use crate::utils::{span_lint, span_lint_and_then};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
 use syntax::ast::LitKind;
-use syntax::codemap::Span;
-use crate::utils::{span_lint, span_lint_and_then};
-use crate::utils::sugg::Sugg;
-use crate::consts::{constant, Constant};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for incompatible bit masks in comparisons.
-///
-/// The formula for detecting if an expression of the type `_ <bit_op> m
-/// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
-/// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
-/// table:
-///
-/// |Comparison  |Bit Op|Example     |is always|Formula               |
-/// |------------|------|------------|---------|----------------------|
-/// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
-/// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
-/// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
-/// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
-/// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
-/// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
-///
-/// **Why is this bad?** If the bits that the comparison cares about are always
-/// set to zero or one by the bit mask, the comparison is constant `true` or
-/// `false` (depending on mask, compared value, and operators).
-///
-/// So the code is actively misleading, and the only reason someone would write
-/// this intentionally is to win an underhanded Rust contest or create a
-/// test-case for this lint.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if (x & 1 == 2) { … }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for incompatible bit masks in comparisons.
+    ///
+    /// The formula for detecting if an expression of the type `_ <bit_op> m
+    /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
+    /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
+    /// table:
+    ///
+    /// |Comparison  |Bit Op|Example     |is always|Formula               |
+    /// |------------|------|------------|---------|----------------------|
+    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
+    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
+    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
+    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
+    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
+    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
+    ///
+    /// **Why is this bad?** If the bits that the comparison cares about are always
+    /// set to zero or one by the bit mask, the comparison is constant `true` or
+    /// `false` (depending on mask, compared value, and operators).
+    ///
+    /// So the code is actively misleading, and the only reason someone would write
+    /// this intentionally is to win an underhanded Rust contest or create a
+    /// test-case for this lint.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let x = 1;
+    /// if (x & 1 == 2) { }
+    /// ```
     pub BAD_BIT_MASK,
     correctness,
     "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
 }
 
-/// **What it does:** Checks for bit masks in comparisons which can be removed
-/// without changing the outcome. The basic structure can be seen in the
-/// following table:
-///
-/// |Comparison| Bit Op  |Example    |equals |
-/// |----------|---------|-----------|-------|
-/// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
-/// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
-///
-/// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
-/// but still a bit misleading, because the bit mask is ineffective.
-///
-/// **Known problems:** False negatives: This lint will only match instances
-/// where we have figured out the math (which is for a power-of-two compared
-/// value). This means things like `x | 1 >= 7` (which would be better written
-/// as `x >= 6`) will not be reported (but bit masks like this are fairly
-/// uncommon).
-///
-/// **Example:**
-/// ```rust
-/// if (x | 1 > 3) { … }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for bit masks in comparisons which can be removed
+    /// without changing the outcome. The basic structure can be seen in the
+    /// following table:
+    ///
+    /// |Comparison| Bit Op  |Example    |equals |
+    /// |----------|---------|-----------|-------|
+    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
+    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
+    ///
+    /// **Why is this bad?** Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
+    /// but still a bit misleading, because the bit mask is ineffective.
+    ///
+    /// **Known problems:** False negatives: This lint will only match instances
+    /// where we have figured out the math (which is for a power-of-two compared
+    /// value). This means things like `x | 1 >= 7` (which would be better written
+    /// as `x >= 6`) will not be reported (but bit masks like this are fairly
+    /// uncommon).
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let x = 1;
+    /// if (x | 1 > 3) {  }
+    /// ```
     pub INEFFECTIVE_BIT_MASK,
     correctness,
-    "expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`"
+    "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
 }
 
-/// **What it does:** Checks for bit masks that can be replaced by a call
-/// to `trailing_zeros`
-///
-/// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15
-/// == 0`
-///
-/// **Known problems:** llvm generates better code for `x & 15 == 0` on x86
-///
-/// **Example:**
-/// ```rust
-/// x & 0x1111 == 0
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for bit masks that can be replaced by a call
+    /// to `trailing_zeros`
+    ///
+    /// **Why is this bad?** `x.trailing_zeros() > 4` is much clearer than `x & 15
+    /// == 0`
+    ///
+    /// **Known problems:** llvm generates better code for `x & 15 == 0` on x86
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let x = 1;
+    /// if x & 0x1111 == 0 { }
+    /// ```
     pub VERBOSE_BIT_MASK,
     style,
     "expressions where a bit mask is less readable than the corresponding method call"
@@ -103,15 +107,11 @@ pub fn new(verbose_bit_mask_threshold: u64) -> Self {
     }
 }
 
-impl LintPass for BitMask {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK)
-    }
-}
+impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if let ExprKind::Binary(ref cmp, ref left, ref right) = e.node {
+        if let ExprKind::Binary(cmp, left, right) = &e.node {
             if cmp.node.is_comparison() {
                 if let Some(cmp_opt) = fetch_int_literal(cx, right) {
                     check_compare(cx, left, cmp.node, cmp_opt, e.span)
@@ -121,13 +121,13 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
             }
         }
         if_chain! {
-            if let ExprKind::Binary(ref op, ref left, ref right) = e.node;
+            if let ExprKind::Binary(op, left, right) = &e.node;
             if BinOpKind::Eq == op.node;
-            if let ExprKind::Binary(ref op1, ref left1, ref right1) = left.node;
+            if let ExprKind::Binary(op1, left1, right1) = &left.node;
             if BinOpKind::BitAnd == op1.node;
-            if let ExprKind::Lit(ref lit) = right1.node;
+            if let ExprKind::Lit(lit) = &right1.node;
             if let LitKind::Int(n, _) = lit.node;
-            if let ExprKind::Lit(ref lit1) = right.node;
+            if let ExprKind::Lit(lit1) = &right.node;
             if let LitKind::Int(0, _) = lit1.node;
             if n.leading_zeros() == n.count_zeros();
             if n > u128::from(self.verbose_bit_mask_threshold);
@@ -138,7 +138,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                    "bit mask could be simplified with a call to `trailing_zeros`",
                                    |db| {
                     let sugg = Sugg::hir(cx, left1, "...").maybe_par();
-                    db.span_suggestion(e.span, "try", format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()));
+                    db.span_suggestion(
+                        e.span,
+                        "try",
+                        format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()),
+                        Applicability::MaybeIncorrect,
+                    );
                 });
             }
         }
@@ -157,9 +162,8 @@ fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
     }
 }
 
-
 fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
-    if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node {
+    if let ExprKind::Binary(op, left, right) = &bit_op.node {
         if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
             return;
         }
@@ -169,99 +173,113 @@ fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp
     }
 }
 
-fn check_bit_mask(cx: &LateContext<'_, '_>, bit_op: BinOpKind, cmp_op: BinOpKind, mask_value: u128, cmp_value: u128, span: Span) {
+#[allow(clippy::too_many_lines)]
+fn check_bit_mask(
+    cx: &LateContext<'_, '_>,
+    bit_op: BinOpKind,
+    cmp_op: BinOpKind,
+    mask_value: u128,
+    cmp_value: u128,
+    span: Span,
+) {
     match cmp_op {
         BinOpKind::Eq | BinOpKind::Ne => match bit_op {
-            BinOpKind::BitAnd => if mask_value & cmp_value != cmp_value {
-                if cmp_value != 0 {
+            BinOpKind::BitAnd => {
+                if mask_value & cmp_value != cmp_value {
+                    if cmp_value != 0 {
+                        span_lint(
+                            cx,
+                            BAD_BIT_MASK,
+                            span,
+                            &format!(
+                                "incompatible bit mask: `_ & {}` can never be equal to `{}`",
+                                mask_value, cmp_value
+                            ),
+                        );
+                    }
+                } else if mask_value == 0 {
+                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
+                }
+            },
+            BinOpKind::BitOr => {
+                if mask_value | cmp_value != cmp_value {
                     span_lint(
                         cx,
                         BAD_BIT_MASK,
                         span,
                         &format!(
-                            "incompatible bit mask: `_ & {}` can never be equal to `{}`",
-                            mask_value,
-                            cmp_value
+                            "incompatible bit mask: `_ | {}` can never be equal to `{}`",
+                            mask_value, cmp_value
                         ),
                     );
                 }
-            } else if mask_value == 0 {
-                span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
-            },
-            BinOpKind::BitOr => if mask_value | cmp_value != cmp_value {
-                span_lint(
-                    cx,
-                    BAD_BIT_MASK,
-                    span,
-                    &format!(
-                        "incompatible bit mask: `_ | {}` can never be equal to `{}`",
-                        mask_value,
-                        cmp_value
-                    ),
-                );
             },
             _ => (),
         },
         BinOpKind::Lt | BinOpKind::Ge => match bit_op {
-            BinOpKind::BitAnd => if mask_value < cmp_value {
-                span_lint(
-                    cx,
-                    BAD_BIT_MASK,
-                    span,
-                    &format!(
-                        "incompatible bit mask: `_ & {}` will always be lower than `{}`",
-                        mask_value,
-                        cmp_value
-                    ),
-                );
-            } else if mask_value == 0 {
-                span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
+            BinOpKind::BitAnd => {
+                if mask_value < cmp_value {
+                    span_lint(
+                        cx,
+                        BAD_BIT_MASK,
+                        span,
+                        &format!(
+                            "incompatible bit mask: `_ & {}` will always be lower than `{}`",
+                            mask_value, cmp_value
+                        ),
+                    );
+                } else if mask_value == 0 {
+                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
+                }
             },
-            BinOpKind::BitOr => if mask_value >= cmp_value {
-                span_lint(
-                    cx,
-                    BAD_BIT_MASK,
-                    span,
-                    &format!(
-                        "incompatible bit mask: `_ | {}` will never be lower than `{}`",
-                        mask_value,
-                        cmp_value
-                    ),
-                );
-            } else {
-                check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
+            BinOpKind::BitOr => {
+                if mask_value >= cmp_value {
+                    span_lint(
+                        cx,
+                        BAD_BIT_MASK,
+                        span,
+                        &format!(
+                            "incompatible bit mask: `_ | {}` will never be lower than `{}`",
+                            mask_value, cmp_value
+                        ),
+                    );
+                } else {
+                    check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
+                }
             },
             BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
             _ => (),
         },
         BinOpKind::Le | BinOpKind::Gt => match bit_op {
-            BinOpKind::BitAnd => if mask_value <= cmp_value {
-                span_lint(
-                    cx,
-                    BAD_BIT_MASK,
-                    span,
-                    &format!(
-                        "incompatible bit mask: `_ & {}` will never be higher than `{}`",
-                        mask_value,
-                        cmp_value
-                    ),
-                );
-            } else if mask_value == 0 {
-                span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
+            BinOpKind::BitAnd => {
+                if mask_value <= cmp_value {
+                    span_lint(
+                        cx,
+                        BAD_BIT_MASK,
+                        span,
+                        &format!(
+                            "incompatible bit mask: `_ & {}` will never be higher than `{}`",
+                            mask_value, cmp_value
+                        ),
+                    );
+                } else if mask_value == 0 {
+                    span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
+                }
             },
-            BinOpKind::BitOr => if mask_value > cmp_value {
-                span_lint(
-                    cx,
-                    BAD_BIT_MASK,
-                    span,
-                    &format!(
-                        "incompatible bit mask: `_ | {}` will always be higher than `{}`",
-                        mask_value,
-                        cmp_value
-                    ),
-                );
-            } else {
-                check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
+            BinOpKind::BitOr => {
+                if mask_value > cmp_value {
+                    span_lint(
+                        cx,
+                        BAD_BIT_MASK,
+                        span,
+                        &format!(
+                            "incompatible bit mask: `_ | {}` will always be higher than `{}`",
+                            mask_value, cmp_value
+                        ),
+                    );
+                } else {
+                    check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
+                }
             },
             BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
             _ => (),
@@ -278,9 +296,7 @@ fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
             span,
             &format!(
                 "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
-                op,
-                m,
-                c
+                op, m, c
             ),
         );
     }
@@ -294,9 +310,7 @@ fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
             span,
             &format!(
                 "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
-                op,
-                m,
-                c
+                op, m, c
             ),
         );
     }
index cfec01d14aed98458942775c2272e9e0c38dceb0..33463df14529d70c5dc7798f64dabee1169f59ae 100644 (file)
@@ -1,49 +1,44 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
 use crate::utils::span_lint;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_data_structures::fx::FxHashSet;
 
-/// **What it does:** Checks for usage of blacklisted names for variables, such
-/// as `foo`.
-///
-/// **Why is this bad?** These names are usually placeholder names and should be
-/// avoided.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let foo = 3.14;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of blacklisted names for variables, such
+    /// as `foo`.
+    ///
+    /// **Why is this bad?** These names are usually placeholder names and should be
+    /// avoided.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let foo = 3.14;
+    /// ```
     pub BLACKLISTED_NAME,
     style,
     "usage of a blacklisted/placeholder name"
 }
 
 #[derive(Clone, Debug)]
-pub struct BlackListedName {
-    blacklist: Vec<String>,
+pub struct BlacklistedName {
+    blacklist: FxHashSet<String>,
 }
 
-impl BlackListedName {
-    pub fn new(blacklist: Vec<String>) -> Self {
-        Self {
-            blacklist,
-        }
+impl BlacklistedName {
+    pub fn new(blacklist: FxHashSet<String>) -> Self {
+        Self { blacklist }
     }
 }
 
-impl LintPass for BlackListedName {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BLACKLISTED_NAME)
-    }
-}
+impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlackListedName {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlacklistedName {
     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
-        if let PatKind::Binding(_, _, ident, _) = pat.node {
-            if self.blacklist.iter().any(|s| ident.name == *s) {
+        if let PatKind::Binding(.., ident, _) = pat.node {
+            if self.blacklist.contains(&ident.name.to_string()) {
                 span_lint(
                     cx,
                     BLACKLISTED_NAME,
index f57a3571b579e7a99dde2f87eaf430ea9116178b..786cba9fc7d82640d0d9bfab60faaa1446cbde03 100644 (file)
@@ -1,55 +1,48 @@
+use crate::utils::*;
 use matches::matches;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use crate::utils::*;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for `if` conditions that use blocks to contain an
-/// expression.
-///
-/// **Why is this bad?** It isn't really Rust style, same as using parentheses
-/// to contain expressions.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if { true } ..
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `if` conditions that use blocks to contain an
+    /// expression.
+    ///
+    /// **Why is this bad?** It isn't really Rust style, same as using parentheses
+    /// to contain expressions.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if { true } { /* ... */ }
+    /// ```
     pub BLOCK_IN_IF_CONDITION_EXPR,
     style,
-    "braces that can be eliminated in conditions, e.g. `if { true } ...`"
+    "braces that can be eliminated in conditions, e.g., `if { true } ...`"
 }
 
-/// **What it does:** Checks for `if` conditions that use blocks containing
-/// statements, or conditions that use closures with blocks.
-///
-/// **Why is this bad?** Using blocks in the condition makes it hard to read.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if { let x = somefunc(); x } ..
-/// // or
-/// if somefunc(|x| { x == 47 }) ..
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `if` conditions that use blocks containing
+    /// statements, or conditions that use closures with blocks.
+    ///
+    /// **Why is this bad?** Using blocks in the condition makes it hard to read.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if { let x = somefunc(); x } {}
+    /// // or
+    /// if somefunc(|x| { x == 47 }) {}
+    /// ```
     pub BLOCK_IN_IF_CONDITION_STMT,
     style,
-    "complex blocks in conditions, e.g. `if { let x = true; x } ...`"
+    "complex blocks in conditions, e.g., `if { let x = true; x } ...`"
 }
 
-#[derive(Copy, Clone)]
-pub struct BlockInIfCondition;
-
-impl LintPass for BlockInIfCondition {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT)
-    }
-}
+declare_lint_pass!(BlockInIfCondition => [BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT]);
 
 struct ExVisitor<'a, 'tcx: 'a> {
     found_block: Option<&'tcx Expr>,
@@ -59,9 +52,9 @@ struct ExVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx: 'a> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr) {
         if let ExprKind::Closure(_, _, eid, _, _) = expr.node {
-            let body = self.cx.tcx.hir.body(eid);
+            let body = self.cx.tcx.hir().body(eid);
             let ex = &body.value;
-            if matches!(ex.node, ExprKind::Block(_, _)) {
+            if matches!(ex.node, ExprKind::Block(_, _)) && !in_macro_or_desugar(body.value.span) {
                 self.found_block = Some(ex);
                 return;
             }
@@ -79,14 +72,14 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if let ExprKind::If(ref check, ref then, _) = expr.node {
-            if let ExprKind::Block(ref block, _) = check.node {
+        if let Some((check, then, _)) = higher::if_block(&expr) {
+            if let ExprKind::Block(block, _) = &check.node {
                 if block.rules == DefaultBlock {
                     if block.stmts.is_empty() {
-                        if let Some(ref ex) = block.expr {
+                        if let Some(ex) = &block.expr {
                             // don't dig into the expression here, just suggest that they remove
                             // the block
-                            if in_macro(expr.span) || differing_macro_contexts(expr.span, ex.span) {
+                            if in_macro_or_desugar(expr.span) || differing_macro_contexts(expr.span, ex.span) {
                                 return;
                             }
                             span_help_and_lint(
@@ -102,11 +95,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                             );
                         }
                     } else {
-                        let span = block
-                            .expr
-                            .as_ref()
-                            .map_or_else(|| block.stmts[0].span, |e| e.span);
-                        if in_macro(span) || differing_macro_contexts(expr.span, span) {
+                        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) {
                             return;
                         }
                         // move block higher
@@ -124,10 +114,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     }
                 }
             } else {
-                let mut visitor = ExVisitor {
-                    found_block: None,
-                    cx,
-                };
+                let mut visitor = ExVisitor { found_block: None, cx };
                 walk_expr(&mut visitor, check);
                 if let Some(block) = visitor.found_block {
                     span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);
index f1596476bfda012b65063ec430aa1469c6d9caf0..f58b17e9a29db2494dc0ea04049be3a87d5c6993 100644 (file)
@@ -1,65 +1,67 @@
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
+use crate::utils::sym;
+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,
+};
+use lazy_static::lazy_static;
 use rustc::hir::intravisit::*;
-use syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID};
-use syntax::codemap::{dummy_spanned, Span, DUMMY_SP};
-use syntax::util::ThinVec;
-use crate::utils::{in_macro, paths, match_type, snippet_opt, span_lint_and_then, SpanlessEq, get_trait_def_id, implements_trait};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::Applicability;
+use syntax::ast::LitKind;
+use syntax::source_map::{dummy_spanned, Span, DUMMY_SP};
+use syntax::symbol::Symbol;
 
-/// **What it does:** Checks for boolean expressions that can be written more
-/// concisely.
-///
-/// **Why is this bad?** Readability of boolean expressions suffers from
-/// unnecessary duplication.
-///
-/// **Known problems:** Ignores short circuiting behavior of `||` and
-/// `&&`. Ignores `|`, `&` and `^`.
-///
-/// **Example:**
-/// ```rust
-/// if a && true  // should be: if a
-/// if !(a == b)  // should be: if a != b
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for boolean expressions that can be written more
+    /// concisely.
+    ///
+    /// **Why is this bad?** Readability of boolean expressions suffers from
+    /// unnecessary duplication.
+    ///
+    /// **Known problems:** Ignores short circuiting behavior of `||` and
+    /// `&&`. Ignores `|`, `&` and `^`.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if a && true  // should be: if a
+    /// if !(a == b)  // should be: if a != b
+    /// ```
     pub NONMINIMAL_BOOL,
     complexity,
     "boolean expressions that can be written more concisely"
 }
 
-/// **What it does:** Checks for boolean expressions that contain terminals that
-/// can be eliminated.
-///
-/// **Why is this bad?** This is most likely a logic bug.
-///
-/// **Known problems:** Ignores short circuiting behavior.
-///
-/// **Example:**
-/// ```rust
-/// if a && b || a { ... }
-/// ```
-/// The `b` is unnecessary, the expression is equivalent to `if a`.
 declare_clippy_lint! {
+    /// **What it does:** Checks for boolean expressions that contain terminals that
+    /// can be eliminated.
+    ///
+    /// **Why is this bad?** This is most likely a logic bug.
+    ///
+    /// **Known problems:** Ignores short circuiting behavior.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if a && b || a { ... }
+    /// ```
+    /// The `b` is unnecessary, the expression is equivalent to `if a`.
     pub LOGIC_BUG,
     correctness,
     "boolean expressions that contain terminals which can be eliminated"
 }
 
+lazy_static! {
 // For each pairs, both orders are considered.
-const METHODS_WITH_NEGATION: [(&str, &str); 2] = [
-    ("is_some", "is_none"),
-    ("is_err", "is_ok"),
+static ref METHODS_WITH_NEGATION: [(Symbol, Symbol); 2] = [
+    (*sym::is_some, *sym::is_none),
+    (*sym::is_err, *sym::is_ok),
 ];
-
-#[derive(Copy, Clone)]
-pub struct NonminimalBool;
-
-impl LintPass for NonminimalBool {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NONMINIMAL_BOOL, LOGIC_BUG)
-    }
 }
 
+declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]);
+
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonminimalBool {
     fn check_fn(
         &mut self,
@@ -68,7 +70,7 @@ fn check_fn(
         _: &'tcx FnDecl,
         body: &'tcx Body,
         _: Span,
-        _: NodeId,
+        _: HirId,
     ) {
         NonminimalBoolVisitor { cx }.visit_body(body)
     }
@@ -87,7 +89,7 @@ struct Hir2Qmm<'a, 'tcx: 'a, 'v> {
 impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
     fn extract(&mut self, op: BinOpKind, a: &[&'v Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
         for a in a {
-            if let ExprKind::Binary(binop, ref lhs, ref rhs) = a.node {
+            if let ExprKind::Binary(binop, lhs, rhs) = &a.node {
                 if binop.node == op {
                     v = self.extract(op, &[lhs, rhs], v)?;
                     continue;
@@ -100,15 +102,15 @@ fn extract(&mut self, op: BinOpKind, a: &[&'v Expr], mut v: Vec<Bool>) -> Result
 
     fn run(&mut self, e: &'v Expr) -> Result<Bool, String> {
         // prevent folding of `cfg!` macros and the like
-        if !in_macro(e.span) {
-            match e.node {
-                ExprKind::Unary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)),
-                ExprKind::Binary(binop, ref lhs, ref rhs) => match binop.node {
+        if !in_macro_or_desugar(e.span) {
+            match &e.node {
+                ExprKind::Unary(UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)),
+                ExprKind::Binary(binop, lhs, rhs) => match &binop.node {
                     BinOpKind::Or => return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?)),
                     BinOpKind::And => return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?)),
                     _ => (),
                 },
-                ExprKind::Lit(ref lit) => match lit.node {
+                ExprKind::Lit(lit) => match lit.node {
                     LitKind::Bool(true) => return Ok(Bool::True),
                     LitKind::Bool(false) => return Ok(Bool::False),
                     _ => (),
@@ -118,24 +120,20 @@ fn run(&mut self, e: &'v Expr) -> Result<Bool, String> {
         }
         for (n, expr) in self.terminals.iter().enumerate() {
             if SpanlessEq::new(self.cx).ignore_fn().eq_expr(e, expr) {
-                #[allow(cast_possible_truncation)]
+                #[allow(clippy::cast_possible_truncation)]
                 return Ok(Bool::Term(n as u8));
             }
-            let negated = match e.node {
-                ExprKind::Binary(binop, ref lhs, ref rhs) => {
-
+            let negated = match &e.node {
+                ExprKind::Binary(binop, lhs, rhs) => {
                     if !implements_ord(self.cx, lhs) {
                         continue;
                     }
 
-                    let mk_expr = |op| {
-                        Expr {
-                            id: DUMMY_NODE_ID,
-                            hir_id: DUMMY_HIR_ID,
-                            span: DUMMY_SP,
-                            attrs: ThinVec::new(),
-                            node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
-                        }
+                    let mk_expr = |op| Expr {
+                        hir_id: DUMMY_HIR_ID,
+                        span: DUMMY_SP,
+                        attrs: ThinVec::new(),
+                        node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
                     };
                     match binop.node {
                         BinOpKind::Eq => mk_expr(BinOpKind::Ne),
@@ -150,14 +148,14 @@ fn run(&mut self, e: &'v Expr) -> Result<Bool, String> {
                 _ => continue,
             };
             if SpanlessEq::new(self.cx).ignore_fn().eq_expr(&negated, expr) {
-                #[allow(cast_possible_truncation)]
+                #[allow(clippy::cast_possible_truncation)]
                 return Ok(Bool::Not(Box::new(Bool::Term(n as u8))));
             }
         }
         let n = self.terminals.len();
         self.terminals.push(e);
         if n < 32 {
-            #[allow(cast_possible_truncation)]
+            #[allow(clippy::cast_possible_truncation)]
             Ok(Bool::Term(n as u8))
         } else {
             Err("too many literals".to_owned())
@@ -178,9 +176,8 @@ fn snip(&self, e: &Expr) -> Option<String> {
     }
 
     fn simplify_not(&self, expr: &Expr) -> Option<String> {
-        match expr.node {
-            ExprKind::Binary(binop, ref lhs, ref rhs) => {
-
+        match &expr.node {
+            ExprKind::Binary(binop, lhs, rhs) => {
                 if !implements_ord(self.cx, lhs) {
                     return None;
                 }
@@ -193,18 +190,21 @@ fn simplify_not(&self, expr: &Expr) -> Option<String> {
                     BinOpKind::Le => Some(" > "),
                     BinOpKind::Ge => Some(" < "),
                     _ => None,
-                }.and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?)))
+                }
+                .and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?)))
             },
-            ExprKind::MethodCall(ref path, _, ref args) if args.len() == 1 => {
+            ExprKind::MethodCall(path, _, args) if args.len() == 1 => {
                 let type_of_receiver = self.cx.tables.expr_ty(&args[0]);
-                if !match_type(self.cx, type_of_receiver, &paths::OPTION) &&
-                    !match_type(self.cx, type_of_receiver, &paths::RESULT) {
-                        return None;
+                if !match_type(self.cx, type_of_receiver, &*paths::OPTION)
+                    && !match_type(self.cx, type_of_receiver, &*paths::RESULT)
+                {
+                    return None;
                 }
                 METHODS_WITH_NEGATION
-                    .iter().cloned()
+                    .iter()
+                    .cloned()
                     .flat_map(|(a, b)| vec![(a, b), (b, a)])
-                    .find(|&(a, _)| a == path.ident.as_str())
+                    .find(|&(a, _)| a == path.ident.name)
                     .and_then(|(_, neg_method)| Some(format!("{}.{}()", self.snip(&args[0])?, neg_method)))
             },
             _ => None,
@@ -213,14 +213,14 @@ fn simplify_not(&self, expr: &Expr) -> Option<String> {
 
     fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
         use quine_mc_cluskey::Bool::*;
-        match *suggestion {
+        match suggestion {
             True => {
                 self.output.push_str("true");
             },
             False => {
                 self.output.push_str("false");
             },
-            Not(ref inner) => match **inner {
+            Not(inner) => match **inner {
                 And(_) | Or(_) => {
                     self.output.push('!');
                     self.output.push('(');
@@ -243,7 +243,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                     self.recurse(inner)?;
                 },
             },
-            And(ref v) => {
+            And(v) => {
                 for (index, inner) in v.iter().enumerate() {
                     if index > 0 {
                         self.output.push_str(" && ");
@@ -257,7 +257,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                     }
                 }
             },
-            Or(ref v) => {
+            Or(v) => {
                 for (index, inner) in v.iter().enumerate() {
                     if index > 0 {
                         self.output.push_str(" || ");
@@ -265,7 +265,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                     self.recurse(inner);
                 }
             },
-            Term(n) => {
+            &Term(n) => {
                 let snip = self.snip(self.terminals[n as usize])?;
                 self.output.push_str(&snip);
             },
@@ -317,22 +317,22 @@ struct Stats {
 
 fn terminal_stats(b: &Bool) -> Stats {
     fn recurse(b: &Bool, stats: &mut Stats) {
-        match *b {
+        match b {
             True | False => stats.ops += 1,
-            Not(ref inner) => {
+            Not(inner) => {
                 match **inner {
                     And(_) | Or(_) => stats.ops += 1, // brackets are also operations
                     _ => stats.negations += 1,
                 }
                 recurse(inner, stats);
             },
-            And(ref v) | Or(ref v) => {
+            And(v) | Or(v) => {
                 stats.ops += v.len() - 1;
                 for inner in v {
                     recurse(inner, stats);
                 }
             },
-            Term(n) => stats.terminals[n as usize] += 1,
+            &Term(n) => stats.terminals[n as usize] += 1,
         }
     }
     use quine_mc_cluskey::Bool::*;
@@ -394,6 +394,9 @@ fn bool_expr(&self, e: &Expr) {
                                     e.span,
                                     "it would look like the following",
                                     suggest(self.cx, suggestion, &h2q.terminals).0,
+                                    // nonminimal_bool can produce minimal but
+                                    // not human readable expressions (#3141)
+                                    Applicability::Unspecified,
                                 );
                             },
                         );
@@ -410,13 +413,22 @@ fn bool_expr(&self, e: &Expr) {
                     improvements.push(suggestion);
                 }
             }
-            let nonminimal_bool_lint = |suggestions| {
+            let nonminimal_bool_lint = |suggestions: Vec<_>| {
                 span_lint_and_then(
                     self.cx,
                     NONMINIMAL_BOOL,
                     e.span,
                     "this boolean expression can be simplified",
-                    |db| { db.span_suggestions(e.span, "try", suggestions); },
+                    |db| {
+                        db.span_suggestions(
+                            e.span,
+                            "try",
+                            suggestions.into_iter(),
+                            // nonminimal_bool can produce minimal but
+                            // not human readable expressions (#3141)
+                            Applicability::Unspecified,
+                        );
+                    },
                 );
             };
             if improvements.is_empty() {
@@ -429,7 +441,7 @@ fn bool_expr(&self, e: &Expr) {
                     improvements
                         .into_iter()
                         .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals).0)
-                        .collect()
+                        .collect(),
                 );
             }
         }
@@ -441,12 +453,16 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
         if in_macro(e.span) {
             return;
         }
-        match e.node {
-            ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => self.bool_expr(e),
-            ExprKind::Unary(UnNot, ref inner) => if self.cx.tables.node_types()[inner.hir_id].is_bool() {
-                self.bool_expr(e);
-            } else {
-                walk_expr(self, e);
+        match &e.node {
+            ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
+                self.bool_expr(e)
+            },
+            ExprKind::Unary(UnNot, inner) => {
+                if self.cx.tables.node_types()[inner.hir_id].is_bool() {
+                    self.bool_expr(e);
+                } else {
+                    walk_expr(self, e);
+                }
             },
             _ => walk_expr(self, e),
         }
@@ -456,9 +472,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-
 fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr) -> bool {
     let ty = cx.tables.expr_ty(expr);
-    get_trait_def_id(cx, &paths::ORD)
-        .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+    get_trait_def_id(cx, &*paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
 }
index 2d4279d3cc19d0dccc0bcb908ed40c1f5846f30d..e9b0ae6797c4d40046b84430014dc17beaa09eeb 100644 (file)
@@ -1,54 +1,51 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{
+    contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability,
+    span_lint_and_sugg, walk_ptrs_ty,
+};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ast::{Name, UintTy};
-use crate::utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg,
-            walk_ptrs_ty};
 
-/// **What it does:** Checks for naive byte counts
-///
-/// **Why is this bad?** The [`bytecount`](https://crates.io/crates/bytecount)
-/// crate has methods to count your bytes faster, especially for large slices.
-///
-/// **Known problems:** If you have predominantly small slices, the
-/// `bytecount::count(..)` method may actually be slower. However, if you can
-/// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
-/// faster in those cases.
-///
-/// **Example:**
-///
-/// ```rust
-/// &my_data.filter(|&x| x == 0u8).count() // use bytecount::count instead
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for naive byte counts
+    ///
+    /// **Why is this bad?** The [`bytecount`](https://crates.io/crates/bytecount)
+    /// crate has methods to count your bytes faster, especially for large slices.
+    ///
+    /// **Known problems:** If you have predominantly small slices, the
+    /// `bytecount::count(..)` method may actually be slower. However, if you can
+    /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
+    /// faster in those cases.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// &my_data.filter(|&x| x == 0u8).count() // use bytecount::count instead
+    /// ```
     pub NAIVE_BYTECOUNT,
     perf,
     "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
 }
 
-#[derive(Copy, Clone)]
-pub struct ByteCount;
-
-impl LintPass for ByteCount {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NAIVE_BYTECOUNT)
-    }
-}
+declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount {
     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
         if_chain! {
             if let ExprKind::MethodCall(ref count, _, ref count_args) = expr.node;
-            if count.ident.name == "count";
+            if count.ident.name == *sym::count;
             if count_args.len() == 1;
             if let ExprKind::MethodCall(ref filter, _, ref filter_args) = count_args[0].node;
-            if filter.ident.name == "filter";
+            if filter.ident.name == *sym::filter;
             if filter_args.len() == 2;
             if let ExprKind::Closure(_, _, body_id, _, _) = filter_args[1].node;
             then {
-                let body = cx.tcx.hir.body(body_id);
+                let body = cx.tcx.hir().body(body_id);
                 if_chain! {
                     if body.arguments.len() == 1;
                     if let Some(argname) = get_pat_name(&body.arguments[0].pat);
@@ -56,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
                     if op.node == BinOpKind::Eq;
                     if match_type(cx,
                                walk_ptrs_ty(cx.tables.expr_ty(&filter_args[0])),
-                               &paths::SLICE_ITER);
+                               &*paths::SLICE_ITER);
                     then {
                         let needle = match get_path_name(l) {
                             Some(name) if check_arg(name, argname, r) => r,
@@ -65,13 +62,13 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
                                 _ => { return; }
                             }
                         };
-                        if ty::TyUint(UintTy::U8) != walk_ptrs_ty(cx.tables.expr_ty(needle)).sty {
+                        if ty::Uint(UintTy::U8) != walk_ptrs_ty(cx.tables.expr_ty(needle)).sty {
                             return;
                         }
                         let haystack = if let ExprKind::MethodCall(ref path, _, ref args) =
                                 filter_args[0].node {
                             let p = path.ident.name;
-                            if (p == "iter" || p == "iter_mut") && args.len() == 1 {
+                            if (p == *sym::iter || p == *sym::iter_mut) && args.len() == 1 {
                                 &args[0]
                             } else {
                                 &filter_args[0]
@@ -79,14 +76,18 @@ fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
                         } else {
                             &filter_args[0]
                         };
-                        span_lint_and_sugg(cx,
-                                           NAIVE_BYTECOUNT,
-                                           expr.span,
-                                           "You appear to be counting bytes the naive way",
-                                           "Consider using the bytecount crate",
-                                           format!("bytecount::count({}, {})",
-                                                    snippet(cx, haystack.span, ".."),
-                                                    snippet(cx, needle.span, "..")));
+                        let mut applicability = Applicability::MaybeIncorrect;
+                        span_lint_and_sugg(
+                            cx,
+                            NAIVE_BYTECOUNT,
+                            expr.span,
+                            "You appear to be counting bytes the naive way",
+                            "Consider using the bytecount crate",
+                            format!("bytecount::count({}, {})",
+                                    snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
+                                    snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
+                            applicability,
+                        );
                     }
                 };
             }
@@ -101,10 +102,12 @@ fn check_arg(name: Name, arg: Name, needle: &Expr) -> bool {
 fn get_path_name(expr: &Expr) -> Option<Name> {
     match expr.node {
         ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) | ExprKind::Unary(UnOp::UnDeref, ref e) => get_path_name(e),
-        ExprKind::Block(ref b, _) => if b.stmts.is_empty() {
-            b.expr.as_ref().and_then(|p| get_path_name(p))
-        } else {
-            None
+        ExprKind::Block(ref b, _) => {
+            if b.stmts.is_empty() {
+                b.expr.as_ref().and_then(|p| get_path_name(p))
+            } else {
+                None
+            }
         },
         ExprKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
         _ => None,
diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs
new file mode 100644 (file)
index 0000000..23532c4
--- /dev/null
@@ -0,0 +1,100 @@
+//! lint on missing cargo common metadata
+
+use crate::utils::span_lint;
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::{ast::*, source_map::DUMMY_SP};
+
+use cargo_metadata;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks to see if all common metadata is defined in
+    /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
+    ///
+    /// **Why is this bad?** It will be more difficult for users to discover the
+    /// purpose of the crate, and key information related to it.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```toml
+    /// # This `Cargo.toml` is missing an authors field:
+    /// [package]
+    /// name = "clippy"
+    /// version = "0.0.212"
+    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
+    /// repository = "https://github.com/rust-lang/rust-clippy"
+    /// readme = "README.md"
+    /// license = "MIT/Apache-2.0"
+    /// keywords = ["clippy", "lint", "plugin"]
+    /// categories = ["development-tools", "development-tools::cargo-plugins"]
+    /// ```
+    pub CARGO_COMMON_METADATA,
+    cargo,
+    "common metadata is defined in `Cargo.toml`"
+}
+
+fn warning(cx: &EarlyContext<'_>, message: &str) {
+    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
+}
+
+fn missing_warning(cx: &EarlyContext<'_>, package: &cargo_metadata::Package, field: &str) {
+    let message = format!("package `{}` is missing `{}` metadata", package.name, field);
+    warning(cx, &message);
+}
+
+fn is_empty_str(value: &Option<String>) -> bool {
+    match value {
+        None => true,
+        Some(value) if value.is_empty() => true,
+        _ => false,
+    }
+}
+
+fn is_empty_vec(value: &[String]) -> bool {
+    // This works because empty iterators return true
+    value.iter().all(std::string::String::is_empty)
+}
+
+declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]);
+
+impl EarlyLintPass for CargoCommonMetadata {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
+        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
+            metadata
+        } else {
+            warning(cx, "could not read cargo metadata");
+            return;
+        };
+
+        for package in metadata.packages {
+            if is_empty_vec(&package.authors) {
+                missing_warning(cx, &package, "package.authors");
+            }
+
+            if is_empty_str(&package.description) {
+                missing_warning(cx, &package, "package.description");
+            }
+
+            if is_empty_str(&package.license) {
+                missing_warning(cx, &package, "package.license");
+            }
+
+            if is_empty_str(&package.repository) {
+                missing_warning(cx, &package, "package.repository");
+            }
+
+            if is_empty_str(&package.readme) {
+                missing_warning(cx, &package, "package.readme");
+            }
+
+            if is_empty_vec(&package.keywords) {
+                missing_warning(cx, &package, "package.keywords");
+            }
+
+            if is_empty_vec(&package.categories) {
+                missing_warning(cx, &package, "package.categories");
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs
new file mode 100644 (file)
index 0000000..bc2542f
--- /dev/null
@@ -0,0 +1,230 @@
+//! calculate cognitive complexity and warn about overly complex functions
+
+use rustc::cfg::CFG;
+use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::ty;
+use rustc::{declare_tool_lint, impl_lint_pass};
+use syntax::ast::Attribute;
+use syntax::source_map::Span;
+
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, is_allowed, match_type, paths, span_help_and_lint, LimitStack};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for methods with high cognitive complexity.
+    ///
+    /// **Why is this bad?** Methods of high cognitive complexity tend to be hard to
+    /// both read and maintain. Also LLVM will tend to optimize small methods better.
+    ///
+    /// **Known problems:** Sometimes it's hard to find a way to reduce the
+    /// complexity.
+    ///
+    /// **Example:** No. You'll see it when you get the warning.
+    pub COGNITIVE_COMPLEXITY,
+    complexity,
+    "functions that should be split up into multiple functions"
+}
+
+pub struct CognitiveComplexity {
+    limit: LimitStack,
+}
+
+impl CognitiveComplexity {
+    pub fn new(limit: u64) -> Self {
+        Self {
+            limit: LimitStack::new(limit),
+        }
+    }
+}
+
+impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
+
+impl CognitiveComplexity {
+    fn check<'a, 'tcx: 'a>(&mut self, cx: &'a LateContext<'a, 'tcx>, body: &'tcx Body, span: Span) {
+        if in_macro_or_desugar(span) {
+            return;
+        }
+
+        let cfg = CFG::new(cx.tcx, body);
+        let expr = &body.value;
+        let n = cfg.graph.len_nodes() as u64;
+        let e = cfg.graph.len_edges() as u64;
+        if e + 2 < n {
+            // the function has unreachable code, other lints should catch this
+            return;
+        }
+        let cc = e + 2 - n;
+        let mut helper = CCHelper {
+            match_arms: 0,
+            divergence: 0,
+            short_circuits: 0,
+            returns: 0,
+            cx,
+        };
+        helper.visit_expr(expr);
+        let CCHelper {
+            match_arms,
+            divergence,
+            short_circuits,
+            returns,
+            ..
+        } = helper;
+        let ret_ty = cx.tables.node_type(expr.hir_id);
+        let ret_adjust = if match_type(cx, ret_ty, &*paths::RESULT) {
+            returns
+        } else {
+            returns / 2
+        };
+
+        if cc + divergence < match_arms + short_circuits {
+            report_cc_bug(
+                cx,
+                cc,
+                match_arms,
+                divergence,
+                short_circuits,
+                ret_adjust,
+                span,
+                body.id().hir_id,
+            );
+        } else {
+            let mut rust_cc = cc + divergence - match_arms - short_circuits;
+            // prevent degenerate cases where unreachable code contains `return` statements
+            if rust_cc >= ret_adjust {
+                rust_cc -= ret_adjust;
+            }
+            if rust_cc > self.limit.limit() {
+                span_help_and_lint(
+                    cx,
+                    COGNITIVE_COMPLEXITY,
+                    span,
+                    &format!("the function has a cognitive complexity of {}", rust_cc),
+                    "you could split it up into multiple smaller functions",
+                );
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CognitiveComplexity {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        _: intravisit::FnKind<'tcx>,
+        _: &'tcx FnDecl,
+        body: &'tcx Body,
+        span: Span,
+        hir_id: HirId,
+    ) {
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id);
+        if !cx.tcx.has_attr(def_id, *sym::test) {
+            self.check(cx, body, span);
+        }
+    }
+
+    fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
+        self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity");
+    }
+    fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
+        self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity");
+    }
+}
+
+struct CCHelper<'a, 'tcx: 'a> {
+    match_arms: u64,
+    divergence: u64,
+    returns: u64,
+    short_circuits: u64, // && and ||
+    cx: &'a LateContext<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
+    fn visit_expr(&mut self, e: &'tcx Expr) {
+        match e.node {
+            ExprKind::Match(_, ref arms, _) => {
+                walk_expr(self, e);
+                let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum();
+                if arms_n > 1 {
+                    self.match_arms += arms_n - 2;
+                }
+            },
+            ExprKind::Call(ref callee, _) => {
+                walk_expr(self, e);
+                let ty = self.cx.tables.node_type(callee.hir_id);
+                match ty.sty {
+                    ty::FnDef(..) | ty::FnPtr(_) => {
+                        let sig = ty.fn_sig(self.cx.tcx);
+                        if sig.skip_binder().output().sty == ty::Never {
+                            self.divergence += 1;
+                        }
+                    },
+                    _ => (),
+                }
+            },
+            ExprKind::Closure(.., _) => (),
+            ExprKind::Binary(op, _, _) => {
+                walk_expr(self, e);
+                match op.node {
+                    BinOpKind::And | BinOpKind::Or => self.short_circuits += 1,
+                    _ => (),
+                }
+            },
+            ExprKind::Ret(_) => self.returns += 1,
+            _ => walk_expr(self, e),
+        }
+    }
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+}
+
+#[cfg(feature = "debugging")]
+#[allow(clippy::too_many_arguments)]
+fn report_cc_bug(
+    _: &LateContext<'_, '_>,
+    cc: u64,
+    narms: u64,
+    div: u64,
+    shorts: u64,
+    returns: u64,
+    span: Span,
+    _: HirId,
+) {
+    span_bug!(
+        span,
+        "Clippy encountered a bug calculating cognitive complexity: cc = {}, arms = {}, \
+         div = {}, shorts = {}, returns = {}. Please file a bug report.",
+        cc,
+        narms,
+        div,
+        shorts,
+        returns
+    );
+}
+#[cfg(not(feature = "debugging"))]
+#[allow(clippy::too_many_arguments)]
+fn report_cc_bug(
+    cx: &LateContext<'_, '_>,
+    cc: u64,
+    narms: u64,
+    div: u64,
+    shorts: u64,
+    returns: u64,
+    span: Span,
+    id: HirId,
+) {
+    if !is_allowed(cx, COGNITIVE_COMPLEXITY, id) {
+        cx.sess().span_note_without_error(
+            span,
+            &format!(
+                "Clippy encountered a bug calculating cognitive complexity \
+                 (hide this message with `#[allow(cognitive_complexity)]`): \
+                 cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \
+                 Please file a bug report.",
+                cc, narms, div, shorts, returns
+            ),
+        );
+    }
+}
index 2771006aad3b40652dae6e7f4bd8ae932e628661..00d7bf3b5a9eecdb429f8788b80ff12920ae739e 100644 (file)
 //!
 //! This lint is **warn** by default
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast;
 
-use crate::utils::{in_macro, snippet_block, span_lint_and_sugg, span_lint_and_then};
 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 rustc_errors::Applicability;
 
-/// **What it does:** Checks for nested `if` statements which can be collapsed
-/// by `&&`-combining their conditions and for `else { if ... }` expressions
-/// that
-/// can be collapsed to `else if ...`.
-///
-/// **Why is this bad?** Each `if`-statement adds one level of nesting, which
-/// makes code look more complex than it really is.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// if x {
-///     if y {
-///         …
-///     }
-/// }
-///
-/// // or
-///
-/// if x {
-///     …
-/// } else {
-///     if y {
-///         …
-///     }
-/// }
-/// ```
-///
-/// Should be written:
-///
-/// ```rust.ignore
-/// if x && y {
-///     …
-/// }
-///
-/// // or
-///
-/// if x {
-///     …
-/// } else if y {
-///     …
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for nested `if` statements which can be collapsed
+    /// by `&&`-combining their conditions and for `else { if ... }` expressions
+    /// that
+    /// can be collapsed to `else if ...`.
+    ///
+    /// **Why is this bad?** Each `if`-statement adds one level of nesting, which
+    /// makes code look more complex than it really is.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// if x {
+    ///     if y {
+    ///         …
+    ///     }
+    /// }
+    ///
+    /// // or
+    ///
+    /// if x {
+    ///     …
+    /// } else {
+    ///     if y {
+    ///         …
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Should be written:
+    ///
+    /// ```rust.ignore
+    /// if x && y {
+    ///     …
+    /// }
+    ///
+    /// // or
+    ///
+    /// if x {
+    ///     …
+    /// } else if y {
+    ///     …
+    /// }
+    /// ```
     pub COLLAPSIBLE_IF,
     style,
-    "`if`s that can be collapsed (e.g. `if x { if y { ... } }` and `else { if x { ... } }`)"
+    "`if`s that can be collapsed (e.g., `if x { if y { ... } }` and `else { if x { ... } }`)"
 }
 
-#[derive(Copy, Clone)]
-pub struct CollapsibleIf;
-
-impl LintPass for CollapsibleIf {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(COLLAPSIBLE_IF)
-    }
-}
+declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF]);
 
 impl EarlyLintPass for CollapsibleIf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
-        if !in_macro(expr.span) {
+        if !in_macro_or_desugar(expr.span) {
             check_if(cx, expr)
         }
     }
@@ -89,10 +85,12 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
 
 fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     match expr.node {
-        ast::ExprKind::If(ref check, ref then, ref else_) => if let Some(ref else_) = *else_ {
-            check_collapsible_maybe_if_let(cx, else_);
-        } else {
-            check_collapsible_no_if_let(cx, expr, check, then);
+        ast::ExprKind::If(ref check, ref then, ref else_) => {
+            if let Some(ref else_) = *else_ {
+                check_collapsible_maybe_if_let(cx, else_);
+            } else {
+                check_collapsible_no_if_let(cx, expr, check, then);
+            }
         },
         ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => {
             check_collapsible_maybe_if_let(cx, else_);
@@ -101,20 +99,33 @@ fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     }
 }
 
+fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
+    // We trim all opening braces and whitespaces and then check if the next string is a comment.
+    let trimmed_block_text = snippet_block(cx, expr.span, "..")
+        .trim_start_matches(|c: char| c.is_whitespace() || c == '{')
+        .to_owned();
+    trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
+}
+
 fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
     if_chain! {
         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(else_.span);
+        if !in_macro_or_desugar(else_.span);
         then {
             match else_.node {
                 ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => {
-                    span_lint_and_sugg(cx,
-                                       COLLAPSIBLE_IF,
-                                       block.span,
-                                       "this `else { if .. }` block can be collapsed",
-                                       "try",
-                                       snippet_block(cx, else_.span, "..").into_owned());
+                    let mut applicability = Applicability::MachineApplicable;
+                    span_lint_and_sugg(
+                        cx,
+                        COLLAPSIBLE_IF,
+                        block.span,
+                        "this `else { if .. }` block can be collapsed",
+                        "try",
+                        snippet_block_with_applicability(cx, else_.span, "..", &mut applicability).into_owned(),
+                        applicability,
+                    );
                 }
                 _ => (),
             }
@@ -124,6 +135,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
 
 fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) {
     if_chain! {
+        if !block_starts_with_comment(cx, then);
         if let Some(inner) = expr_block(then);
         if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.node;
         then {
@@ -133,11 +145,16 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
             span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this if statement can be collapsed", |db| {
                 let lhs = Sugg::ast(cx, check, "..");
                 let rhs = Sugg::ast(cx, check_inner, "..");
-                db.span_suggestion(expr.span,
-                                   "try",
-                                   format!("if {} {}",
-                                           lhs.and(&rhs),
-                                           snippet_block(cx, content.span, "..")));
+                db.span_suggestion(
+                    expr.span,
+                    "try",
+                    format!(
+                        "if {} {}",
+                        lhs.and(&rhs),
+                        snippet_block(cx, content.span, ".."),
+                    ),
+                    Applicability::MachineApplicable, // snippet
+                );
             });
         }
     }
index 1af0741d67fb193973465e0743ced0b7406be611..150d379cc7c7a75dd0b5f2e6338f096d5aa4009c 100644 (file)
@@ -1,37 +1,32 @@
-use syntax::ast::*;
+use crate::utils::{in_macro_or_desugar, snippet, span_lint_and_then};
 use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
-use crate::utils::{in_macro, snippet, span_lint_and_then};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::*;
 
-/// **What it does:** Checks for constants with an explicit `'static` lifetime.
-///
-/// **Why is this bad?** Adding `'static` to every reference can create very
-/// complicated types.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
-/// &[...]
-/// ```
-/// This code can be rewritten as
-/// ```rust
-///  const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for constants with an explicit `'static` lifetime.
+    ///
+    /// **Why is this bad?** Adding `'static` to every reference can create very
+    /// complicated types.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+    /// &[...]
+    /// ```
+    /// This code can be rewritten as
+    /// ```ignore
+    ///  const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+    /// ```
     pub CONST_STATIC_LIFETIME,
     style,
     "Using explicit `'static` lifetime for constants when elision rules would allow omitting them."
 }
 
-pub struct StaticConst;
-
-impl LintPass for StaticConst {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(CONST_STATIC_LIFETIME)
-    }
-}
+declare_lint_pass!(StaticConst => [CONST_STATIC_LIFETIME]);
 
 impl StaticConst {
     // Recursively visit types
@@ -41,17 +36,18 @@ fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) {
             TyKind::Array(ref ty, _) => {
                 self.visit_type(&*ty, cx);
             },
-            TyKind::Tup(ref tup) => for tup_ty in tup {
-                self.visit_type(&*tup_ty, cx);
+            TyKind::Tup(ref tup) => {
+                for tup_ty in tup {
+                    self.visit_type(&*tup_ty, cx);
+                }
             },
             // This is what we are looking for !
             TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
                 // Match the 'static lifetime
                 if let Some(lifetime) = *optional_lifetime {
                     match borrow_type.ty.node {
-                        TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) |
-                        TyKind::Tup(..) => {
-                            if lifetime.ident.name == "'static" {
+                        TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
+                            if lifetime.ident.name == syntax::symbol::keywords::StaticLifetime.name() {
                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
                                 let sugg = format!("&{}", snip);
                                 span_lint_and_then(
@@ -60,12 +56,17 @@ fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) {
                                     lifetime.ident.span,
                                     "Constants have by default a `'static` lifetime",
                                     |db| {
-                                        db.span_suggestion(ty.span, "consider removing `'static`", sugg);
+                                        db.span_suggestion(
+                                            ty.span,
+                                            "consider removing `'static`",
+                                            sugg,
+                                            Applicability::MachineApplicable, //snippet
+                                        );
                                     },
                                 );
                             }
-                        }
-                        _ => {}
+                        },
+                        _ => {},
                     }
                 }
                 self.visit_type(&*borrow_type.ty, cx);
@@ -80,7 +81,7 @@ fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>) {
 
 impl EarlyLintPass for StaticConst {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if !in_macro(item.span) {
+        if !in_macro_or_desugar(item.span) {
             // Match only constants...
             if let ItemKind::Const(ref var_type, _) = item.node {
                 self.visit_type(var_type, cx);
index d116ffafeacdcb614439c1e85dc79783f37b5d11..cbc10768bbc1604dc7b24e0fd395750a5616a9cd 100644 (file)
@@ -1,60 +1,49 @@
-#![allow(cast_possible_truncation)]
-#![allow(float_cmp)]
+#![allow(clippy::float_cmp)]
 
-use rustc::lint::LateContext;
-use rustc::{span_bug, bug};
-use rustc::hir::def::Def;
+use crate::utils::{clip, higher, sext, unsext};
+use if_chain::if_chain;
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::*;
-use rustc::ty::{self, Ty, TyCtxt, Instance};
-use rustc::ty::subst::{Subst, Substs};
+use rustc::lint::LateContext;
+use rustc::ty::subst::{Subst, SubstsRef};
+use rustc::ty::{self, Instance, Ty, TyCtxt};
+use rustc::{bug, span_bug};
+use rustc_data_structures::sync::Lrc;
 use std::cmp::Ordering::{self, Equal};
 use std::cmp::PartialOrd;
+use std::convert::TryFrom;
+use std::convert::TryInto;
 use std::hash::{Hash, Hasher};
-use std::mem;
-use std::rc::Rc;
 use syntax::ast::{FloatTy, LitKind};
-use syntax::ptr::P;
-use crate::utils::{sext, unsext, clip};
-
-#[derive(Debug, Copy, Clone)]
-pub enum FloatWidth {
-    F32,
-    F64,
-    Any,
-}
-
-impl From<FloatTy> for FloatWidth {
-    fn from(ty: FloatTy) -> Self {
-        match ty {
-            FloatTy::F32 => FloatWidth::F32,
-            FloatTy::F64 => FloatWidth::F64,
-        }
-    }
-}
+use syntax_pos::symbol::{LocalInternedString, Symbol};
 
 /// A `LitKind`-like enum to fold constant `Expr`s into.
 #[derive(Debug, Clone)]
 pub enum Constant {
-    /// a String "abc"
+    /// A `String` (e.g., "abc").
     Str(String),
-    /// a Binary String b"abc"
-    Binary(Rc<Vec<u8>>),
-    /// a single char 'a'
+    /// A binary string (e.g., `b"abc"`).
+    Binary(Lrc<Vec<u8>>),
+    /// A single `char` (e.g., `'a'`).
     Char(char),
-    /// an integer's bit representation
+    /// An integer's bit representation.
     Int(u128),
-    /// an f32
+    /// An `f32`.
     F32(f32),
-    /// an f64
+    /// An `f64`.
     F64(f64),
-    /// true or false
+    /// `true` or `false`.
     Bool(bool),
-    /// an array of constants
+    /// An array of constants.
     Vec(Vec<Constant>),
-    /// also an array, but with only one constant, repeated N times
+    /// Also an array, but with only one constant, repeated N times.
     Repeat(Box<Constant>, u64),
-    /// a tuple of constants
+    /// A tuple of constants.
     Tuple(Vec<Constant>),
+    /// A raw pointer.
+    RawPtr(u128),
+    /// A literal with syntax error.
+    Err(Symbol),
 }
 
 impl PartialEq for Constant {
@@ -65,21 +54,24 @@ fn eq(&self, other: &Self) -> bool {
             (&Constant::Char(l), &Constant::Char(r)) => l == r,
             (&Constant::Int(l), &Constant::Int(r)) => l == r,
             (&Constant::F64(l), &Constant::F64(r)) => {
-                // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
-                // `Fw32 == Fw64` so don’t compare them
-                // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs
-                unsafe { mem::transmute::<f64, u64>(l) == mem::transmute::<f64, u64>(r) }
+                // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
+                // `Fw32 == Fw64`, so don’t compare them.
+                // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
+                l.to_bits() == r.to_bits()
             },
             (&Constant::F32(l), &Constant::F32(r)) => {
-                // we want `Fw32 == FwAny` and `FwAny == Fw64`, by transitivity we must have
-                // `Fw32 == Fw64` so don’t compare them
-                // mem::transmute is required to catch non-matching 0.0, -0.0, and NaNs
-                unsafe { mem::transmute::<f64, u64>(f64::from(l)) == mem::transmute::<f64, u64>(f64::from(r)) }
+                // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
+                // `Fw32 == Fw64`, so don’t compare them.
+                // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
+                f64::from(l).to_bits() == f64::from(r).to_bits()
             },
             (&Constant::Bool(l), &Constant::Bool(r)) => l == r,
-            (&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r,
+            (&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => {
+                l == r
+            },
             (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
-            _ => false, // TODO: Are there inter-type equalities?
+            // TODO: are there inter-type equalities?
+            _ => false,
         }
     }
 }
@@ -89,6 +81,7 @@ fn hash<H>(&self, state: &mut H)
     where
         H: Hasher,
     {
+        std::mem::discriminant(self).hash(state);
         match *self {
             Constant::Str(ref s) => {
                 s.hash(state);
@@ -103,10 +96,10 @@ fn hash<H>(&self, state: &mut H)
                 i.hash(state);
             },
             Constant::F32(f) => {
-                unsafe { mem::transmute::<f64, u64>(f64::from(f)) }.hash(state);
+                f64::from(f).to_bits().hash(state);
             },
             Constant::F64(f) => {
-                unsafe { mem::transmute::<f64, u64>(f) }.hash(state);
+                f.to_bits().hash(state);
             },
             Constant::Bool(b) => {
                 b.hash(state);
@@ -118,17 +111,23 @@ fn hash<H>(&self, state: &mut H)
                 c.hash(state);
                 l.hash(state);
             },
+            Constant::RawPtr(u) => {
+                u.hash(state);
+            },
+            Constant::Err(ref s) => {
+                s.hash(state);
+            },
         }
     }
 }
 
 impl Constant {
-    pub fn partial_cmp(tcx: TyCtxt<'_, '_, '_>, cmp_type: &ty::TypeVariants<'_>, left: &Self, right: &Self) -> Option<Ordering> {
+    pub fn partial_cmp(tcx: TyCtxt<'_, '_, '_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
         match (left, right) {
             (&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)),
             (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)),
             (&Constant::Int(l), &Constant::Int(r)) => {
-                if let ty::TyInt(int_ty) = *cmp_type {
+                if let ty::Int(int_ty) = cmp_type.sty {
                     Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
                 } else {
                     Some(l.cmp(&r))
@@ -140,43 +139,48 @@ pub fn partial_cmp(tcx: TyCtxt<'_, '_, '_>, cmp_type: &ty::TypeVariants<'_>, lef
             (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) | (&Constant::Vec(ref l), &Constant::Vec(ref r)) => l
                 .iter()
                 .zip(r.iter())
-                .map(|(li, ri)| Constant::partial_cmp(tcx, cmp_type, li, ri))
+                .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
                 .find(|r| r.map_or(true, |o| o != Ordering::Equal))
                 .unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
             (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => {
-                match Constant::partial_cmp(tcx, cmp_type, lv, rv) {
+                match Self::partial_cmp(tcx, cmp_type, lv, rv) {
                     Some(Equal) => Some(ls.cmp(rs)),
                     x => x,
                 }
             },
-            _ => None, // TODO: Are there any useful inter-type orderings?
+            // TODO: are there any useful inter-type orderings?
+            _ => None,
         }
     }
 }
 
-/// parse a `LitKind` to a `Constant`
+/// Parses a `LitKind` to a `Constant`.
 pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant {
     use syntax::ast::*;
 
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s) => Constant::Binary(Rc::clone(s)),
+        LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
-        LitKind::Float(ref is, _) |
-        LitKind::FloatUnsuffixed(ref is) => match ty.sty {
-            ty::TyFloat(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
-            ty::TyFloat(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
+        LitKind::Float(ref is, _) | LitKind::FloatUnsuffixed(ref is) => match ty.sty {
+            ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
+            ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
             _ => bug!(),
         },
         LitKind::Bool(b) => Constant::Bool(b),
+        LitKind::Err(s) => Constant::Err(s),
     }
 }
 
-pub fn constant<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>, e: &Expr) -> Option<(Constant, bool)> {
+pub fn constant<'c, 'cc>(
+    lcx: &LateContext<'c, 'cc>,
+    tables: &'c ty::TypeckTables<'cc>,
+    e: &Expr,
+) -> Option<(Constant, bool)> {
     let mut cx = ConstEvalLateContext {
-        tcx: lcx.tcx,
+        lcx,
         tables,
         param_env: lcx.param_env,
         needed_resolution: false,
@@ -185,14 +189,21 @@ pub fn constant<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTable
     cx.expr(e).map(|cst| (cst, cx.needed_resolution))
 }
 
-pub fn constant_simple<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>, e: &Expr) -> Option<Constant> {
+pub fn constant_simple<'c, 'cc>(
+    lcx: &LateContext<'c, 'cc>,
+    tables: &'c ty::TypeckTables<'cc>,
+    e: &Expr,
+) -> Option<Constant> {
     constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
 }
 
-/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`
-pub fn constant_context<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>) -> ConstEvalLateContext<'c, 'cc> {
+/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`.
+pub fn constant_context<'c, 'cc>(
+    lcx: &'c LateContext<'c, 'cc>,
+    tables: &'c ty::TypeckTables<'cc>,
+) -> ConstEvalLateContext<'c, 'cc> {
     ConstEvalLateContext {
-        tcx: lcx.tcx,
+        lcx,
         tables,
         param_env: lcx.param_env,
         needed_resolution: false,
@@ -201,29 +212,31 @@ pub fn constant_context<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::Typ
 }
 
 pub struct ConstEvalLateContext<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    lcx: &'a LateContext<'a, 'tcx>,
     tables: &'a ty::TypeckTables<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     needed_resolution: bool,
-    substs: &'tcx Substs<'tcx>,
+    substs: SubstsRef<'tcx>,
 }
 
 impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
-    /// simple constant folding: Insert an expression, get a constant or none.
+    /// Simple constant folding: Insert an expression, get a constant or none.
     pub fn expr(&mut self, e: &Expr) -> Option<Constant> {
+        if let Some((ref cond, ref then, otherwise)) = higher::if_block(&e) {
+            return self.ifthenelse(cond, then, otherwise);
+        }
         match e.node {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id),
             ExprKind::Block(ref block, _) => self.block(block),
-            ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, otherwise),
             ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.tables.expr_ty(e))),
             ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
             ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
             ExprKind::Repeat(ref value, _) => {
                 let n = match self.tables.expr_ty(e).sty {
-                    ty::TyArray(_, n) => n.assert_usize(self.tcx).expect("array length"),
+                    ty::Array(_, n) => n.assert_usize(self.lcx.tcx).expect("array length"),
                     _ => span_bug!(e.span, "typeck error"),
                 };
-                self.expr(value).map(|v| Constant::Repeat(Box::new(v), n as u64))
+                self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
             ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
                 UnNot => self.constant_not(&o, self.tables.expr_ty(e)),
@@ -231,20 +244,49 @@ pub fn expr(&mut self, e: &Expr) -> Option<Constant> {
                 UnDeref => Some(o),
             }),
             ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
-            // TODO: add other expressions
+            ExprKind::Call(ref callee, ref args) => {
+                // We only handle a few const functions for now.
+                if_chain! {
+                    if args.is_empty();
+                    if let ExprKind::Path(qpath) = &callee.node;
+                    let res = self.tables.qpath_res(qpath, callee.hir_id);
+                    if let Some(def_id) = res.opt_def_id();
+                    let def_path = self.lcx.get_def_path(def_id)
+                        .iter()
+                        .map(LocalInternedString::get)
+                        .collect::<Vec<_>>();
+                    if let &["core", "num", impl_ty, "max_value"] = &def_path[..];
+                    then {
+                       let value = match impl_ty {
+                           "<impl i8>" => i8::max_value() as u128,
+                           "<impl i16>" => i16::max_value() as u128,
+                           "<impl i32>" => i32::max_value() as u128,
+                           "<impl i64>" => i64::max_value() as u128,
+                           "<impl i128>" => i128::max_value() as u128,
+                           _ => return None,
+                       };
+                       Some(Constant::Int(value))
+                    }
+                    else {
+                        None
+                    }
+                }
+            },
+            // TODO: add other expressions.
             _ => None,
         }
     }
 
-    fn constant_not(&self, o: &Constant, ty: ty::Ty<'_>) -> Option<Constant> {
+    #[allow(clippy::cast_possible_wrap)]
+    fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
         use self::Constant::*;
         match *o {
             Bool(b) => Some(Bool(!b)),
             Int(value) => {
                 let value = !value;
                 match ty.sty {
-                    ty::TyInt(ity) => Some(Int(unsext(self.tcx, value as i128, ity))),
-                    ty::TyUint(ity) => Some(Int(clip(self.tcx, value, ity))),
+                    ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
+                    ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
                     _ => None,
                 }
             },
@@ -252,19 +294,19 @@ fn constant_not(&self, o: &Constant, ty: ty::Ty<'_>) -> Option<Constant> {
         }
     }
 
-    fn constant_negate(&self, o: &Constant, ty: ty::Ty<'_>) -> Option<Constant> {
+    fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
         use self::Constant::*;
         match *o {
             Int(value) => {
                 let ity = match ty.sty {
-                    ty::TyInt(ity) => ity,
+                    ty::Int(ity) => ity,
                     _ => return None,
                 };
                 // sign extend
-                let value = sext(self.tcx, value, ity);
+                let value = sext(self.lcx.tcx, value, ity);
                 let value = value.checked_neg()?;
                 // clear unused bits
-                Some(Int(unsext(self.tcx, value, ity)))
+                Some(Int(unsext(self.lcx.tcx, value, ity)))
             },
             F32(f) => Some(F32(-f)),
             F64(f) => Some(F64(-f)),
@@ -272,44 +314,44 @@ fn constant_negate(&self, o: &Constant, ty: ty::Ty<'_>) -> Option<Constant> {
         }
     }
 
-    /// create `Some(Vec![..])` of all constants, unless there is any
-    /// non-constant part
+    /// Create `Some(Vec![..])` of all constants, unless there is any
+    /// non-constant part.
     fn multi(&mut self, vec: &[Expr]) -> Option<Vec<Constant>> {
-        vec.iter()
-            .map(|elem| self.expr(elem))
-            .collect::<Option<_>>()
+        vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
     }
 
-    /// lookup a possibly constant expression from a ExprKind::Path
+    /// Lookup a possibly constant expression from a ExprKind::Path.
     fn fetch_path(&mut self, qpath: &QPath, id: HirId) -> Option<Constant> {
-        let def = self.tables.qpath_def(qpath, id);
-        match def {
-            Def::Const(def_id) | Def::AssociatedConst(def_id) => {
+        use rustc::mir::interpret::GlobalId;
+
+        let res = self.tables.qpath_res(qpath, id);
+        match res {
+            Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssociatedConst, def_id) => {
                 let substs = self.tables.node_substs(id);
                 let substs = if self.substs.is_empty() {
                     substs
                 } else {
-                    substs.subst(self.tcx, self.substs)
+                    substs.subst(self.lcx.tcx, self.substs)
                 };
-                let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs)?;
+                let instance = Instance::resolve(self.lcx.tcx, self.param_env, def_id, substs)?;
                 let gid = GlobalId {
                     instance,
                     promoted: None,
                 };
-                use rustc::mir::interpret::GlobalId;
-                let result = self.tcx.const_eval(self.param_env.and(gid)).ok()?;
-                let ret = miri_to_const(self.tcx, result);
-                if ret.is_some() {
+
+                let result = self.lcx.tcx.const_eval(self.param_env.and(gid)).ok()?;
+                let result = miri_to_const(self.lcx.tcx, &result);
+                if result.is_some() {
                     self.needed_resolution = true;
                 }
-                return ret;
+                result
             },
-            _ => {},
+            // FIXME: cover all usable cases.
+            _ => None,
         }
-        None
     }
 
-    /// A block can only yield a constant if it only has one constant expression
+    /// A block can only yield a constant if it only has one constant expression.
     fn block(&mut self, block: &Block) -> Option<Constant> {
         if block.stmts.is_empty() {
             block.expr.as_ref().and_then(|b| self.expr(b))
@@ -318,10 +360,10 @@ fn block(&mut self, block: &Block) -> Option<Constant> {
         }
     }
 
-    fn ifthenelse(&mut self, cond: &Expr, then: &P<Expr>, otherwise: &Option<P<Expr>>) -> Option<Constant> {
+    fn ifthenelse(&mut self, cond: &Expr, then: &Expr, otherwise: Option<&Expr>) -> Option<Constant> {
         if let Some(Constant::Bool(b)) = self.expr(cond) {
             if b {
-                self.expr(&**then)
+                self.expr(&*then)
             } else {
                 otherwise.as_ref().and_then(|expr| self.expr(expr))
             }
@@ -334,55 +376,51 @@ fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> {
         let l = self.expr(left)?;
         let r = self.expr(right);
         match (l, r) {
-            (Constant::Int(l), Some(Constant::Int(r))) => {
-                match self.tables.expr_ty(left).sty {
-                    ty::TyInt(ity) => {
-                        let l = sext(self.tcx, l, ity);
-                        let r = sext(self.tcx, r, ity);
-                        let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
-                        match op.node {
-                            BinOpKind::Add => l.checked_add(r).map(zext),
-                            BinOpKind::Sub => l.checked_sub(r).map(zext),
-                            BinOpKind::Mul => l.checked_mul(r).map(zext),
-                            BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
-                            BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
-                            BinOpKind::Shr => l.checked_shr(r as u128 as u32).map(zext),
-                            BinOpKind::Shl => l.checked_shl(r as u128 as u32).map(zext),
-                            BinOpKind::BitXor => Some(zext(l ^ r)),
-                            BinOpKind::BitOr => Some(zext(l | r)),
-                            BinOpKind::BitAnd => Some(zext(l & r)),
-                            BinOpKind::Eq => Some(Constant::Bool(l == r)),
-                            BinOpKind::Ne => Some(Constant::Bool(l != r)),
-                            BinOpKind::Lt => Some(Constant::Bool(l < r)),
-                            BinOpKind::Le => Some(Constant::Bool(l <= r)),
-                            BinOpKind::Ge => Some(Constant::Bool(l >= r)),
-                            BinOpKind::Gt => Some(Constant::Bool(l > r)),
-                            _ => None,
-                        }
+            (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).sty {
+                ty::Int(ity) => {
+                    let l = sext(self.lcx.tcx, l, ity);
+                    let r = sext(self.lcx.tcx, r, ity);
+                    let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
+                    match op.node {
+                        BinOpKind::Add => l.checked_add(r).map(zext),
+                        BinOpKind::Sub => l.checked_sub(r).map(zext),
+                        BinOpKind::Mul => l.checked_mul(r).map(zext),
+                        BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
+                        BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
+                        BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
+                        BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
+                        BinOpKind::BitXor => Some(zext(l ^ r)),
+                        BinOpKind::BitOr => Some(zext(l | r)),
+                        BinOpKind::BitAnd => Some(zext(l & r)),
+                        BinOpKind::Eq => Some(Constant::Bool(l == r)),
+                        BinOpKind::Ne => Some(Constant::Bool(l != r)),
+                        BinOpKind::Lt => Some(Constant::Bool(l < r)),
+                        BinOpKind::Le => Some(Constant::Bool(l <= r)),
+                        BinOpKind::Ge => Some(Constant::Bool(l >= r)),
+                        BinOpKind::Gt => Some(Constant::Bool(l > r)),
+                        _ => None,
                     }
-                    ty::TyUint(_) => {
-                        match op.node {
-                            BinOpKind::Add => l.checked_add(r).map(Constant::Int),
-                            BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
-                            BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
-                            BinOpKind::Div => l.checked_div(r).map(Constant::Int),
-                            BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
-                            BinOpKind::Shr => l.checked_shr(r as u32).map(Constant::Int),
-                            BinOpKind::Shl => l.checked_shl(r as u32).map(Constant::Int),
-                            BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
-                            BinOpKind::BitOr => Some(Constant::Int(l | r)),
-                            BinOpKind::BitAnd => Some(Constant::Int(l & r)),
-                            BinOpKind::Eq => Some(Constant::Bool(l == r)),
-                            BinOpKind::Ne => Some(Constant::Bool(l != r)),
-                            BinOpKind::Lt => Some(Constant::Bool(l < r)),
-                            BinOpKind::Le => Some(Constant::Bool(l <= r)),
-                            BinOpKind::Ge => Some(Constant::Bool(l >= r)),
-                            BinOpKind::Gt => Some(Constant::Bool(l > r)),
-                            _ => None,
-                        }
-                    },
+                },
+                ty::Uint(_) => match op.node {
+                    BinOpKind::Add => l.checked_add(r).map(Constant::Int),
+                    BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
+                    BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
+                    BinOpKind::Div => l.checked_div(r).map(Constant::Int),
+                    BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
+                    BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
+                    BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
+                    BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
+                    BinOpKind::BitOr => Some(Constant::Int(l | r)),
+                    BinOpKind::BitAnd => Some(Constant::Int(l & r)),
+                    BinOpKind::Eq => Some(Constant::Bool(l == r)),
+                    BinOpKind::Ne => Some(Constant::Bool(l != r)),
+                    BinOpKind::Lt => Some(Constant::Bool(l < r)),
+                    BinOpKind::Le => Some(Constant::Bool(l <= r)),
+                    BinOpKind::Ge => Some(Constant::Bool(l >= r)),
+                    BinOpKind::Gt => Some(Constant::Bool(l > r)),
                     _ => None,
-                }
+                },
+                _ => None,
             },
             (Constant::F32(l), Some(Constant::F32(r))) => match op.node {
                 BinOpKind::Add => Some(Constant::F32(l + r)),
@@ -415,7 +453,9 @@ fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> {
             (l, r) => match (op.node, l, r) {
                 (BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
                 (BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
-                (BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => Some(r),
+                (BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
+                    Some(r)
+                },
                 (BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
                 (BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
                 (BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
@@ -426,32 +466,41 @@ fn binop(&mut self, op: BinOp, left: &Expr, right: &Expr) -> Option<Constant> {
 }
 
 pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<'tcx>) -> Option<Constant> {
-    use rustc::mir::interpret::{Scalar, ConstValue};
+    use rustc::mir::interpret::{ConstValue, Scalar};
     match result.val {
-        ConstValue::Scalar(Scalar::Bits{ bits: b, ..}) => match result.ty.sty {
-            ty::TyBool => Some(Constant::Bool(b == 1)),
-            ty::TyUint(_) | ty::TyInt(_) => Some(Constant::Int(b)),
-            ty::TyFloat(FloatTy::F32) => Some(Constant::F32(f32::from_bits(b as u32))),
-            ty::TyFloat(FloatTy::F64) => Some(Constant::F64(f64::from_bits(b as u64))),
-            // FIXME: implement other conversion
+        ConstValue::Scalar(Scalar::Bits { bits: b, .. }) => match result.ty.sty {
+            ty::Bool => Some(Constant::Bool(b == 1)),
+            ty::Uint(_) | ty::Int(_) => Some(Constant::Int(b)),
+            ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
+                b.try_into().expect("invalid f32 bit representation"),
+            ))),
+            ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
+                b.try_into().expect("invalid f64 bit representation"),
+            ))),
+            ty::RawPtr(type_and_mut) => {
+                if let ty::Uint(_) = type_and_mut.ty.sty {
+                    return Some(Constant::RawPtr(b));
+                }
+                None
+            },
+            // FIXME: implement other conversions.
             _ => None,
         },
-        ConstValue::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: n, .. }) => match result.ty.sty {
-            ty::TyRef(_, tam, _) => match tam.sty {
-                ty::TyStr => {
-                    let alloc = tcx
-                        .alloc_map
-                        .lock()
-                        .unwrap_memory(ptr.alloc_id);
-                    let offset = ptr.offset.bytes() as usize;
-                    let n = n as usize;
-                    String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned()).ok().map(Constant::Str)
+        ConstValue::Slice(Scalar::Ptr(ptr), n) => match result.ty.sty {
+            ty::Ref(_, tam, _) => match tam.sty {
+                ty::Str => {
+                    let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
+                    let offset = ptr.offset.bytes().try_into().expect("too-large pointer offset");
+                    let n = usize::try_from(n).unwrap();
+                    String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned())
+                        .ok()
+                        .map(Constant::Str)
                 },
                 _ => None,
             },
             _ => None,
-        }
-        // FIXME: implement other conversions
+        },
+        // FIXME: implement other conversions.
         _ => None,
     }
 }
index 5709526c6007e2c5ae85d9a3ffd74c8ef0b9ca7d..d85cf97a6bdde3380b8e746ab3f3cce852a15ae1 100644 (file)
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::ty::Ty;
+use crate::utils::{get_parent_expr, higher, in_macro_or_desugar, snippet, span_lint_and_then, span_note_and_lint};
+use crate::utils::{SpanlessEq, SpanlessHash};
 use rustc::hir::*;
-use std::collections::HashMap;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::Ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::FxHashMap;
+use smallvec::SmallVec;
 use std::collections::hash_map::Entry;
+use std::hash::BuildHasherDefault;
 use syntax::symbol::LocalInternedString;
-use syntax::util::small_vector::SmallVector;
-use crate::utils::{SpanlessEq, SpanlessHash};
-use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint};
 
-/// **What it does:** Checks for consecutive `if`s with the same condition.
-///
-/// **Why is this bad?** This is probably a copy & paste error.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-/// ```rust
-/// if a == b {
-///     …
-/// } else if a == b {
-///     …
-/// }
-/// ```
-///
-/// Note that this lint ignores all conditions with a function call as it could
-/// have side effects:
-///
-/// ```rust
-/// if foo() {
-///     …
-/// } else if foo() { // not linted
-///     …
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for consecutive `if`s with the same condition.
+    ///
+    /// **Why is this bad?** This is probably a copy & paste error.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if a == b {
+    ///     …
+    /// } else if a == b {
+    ///     …
+    /// }
+    /// ```
+    ///
+    /// Note that this lint ignores all conditions with a function call as it could
+    /// have side effects:
+    ///
+    /// ```ignore
+    /// if foo() {
+    ///     …
+    /// } else if foo() { // not linted
+    ///     …
+    /// }
+    /// ```
     pub IFS_SAME_COND,
     correctness,
     "consecutive `ifs` with the same condition"
 }
 
-/// **What it does:** Checks for `if/else` with the same body as the *then* part
-/// and the *else* part.
-///
-/// **Why is this bad?** This is probably a copy & paste error.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-/// ```rust
-/// let foo = if … {
-///     42
-/// } else {
-///     42
-/// };
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `if/else` with the same body as the *then* part
+    /// and the *else* part.
+    ///
+    /// **Why is this bad?** This is probably a copy & paste error.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let foo = if … {
+    ///     42
+    /// } else {
+    ///     42
+    /// };
+    /// ```
     pub IF_SAME_THEN_ELSE,
     correctness,
     "if with the same *then* and *else* blocks"
 }
 
-/// **What it does:** Checks for `match` with identical arm bodies.
-///
-/// **Why is this bad?** This is probably a copy & paste error. If arm bodies
-/// are the same on purpose, you can factor them
-/// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
-///
-/// **Known problems:** False positive possible with order dependent `match`
-/// (see issue
-/// [#860](https://github.com/rust-lang-nursery/rust-clippy/issues/860)).
-///
-/// **Example:**
-/// ```rust,ignore
-/// match foo {
-///     Bar => bar(),
-///     Quz => quz(),
-///     Baz => bar(), // <= oops
-/// }
-/// ```
-///
-/// This should probably be
-/// ```rust,ignore
-/// match foo {
-///     Bar => bar(),
-///     Quz => quz(),
-///     Baz => baz(), // <= fixed
-/// }
-/// ```
-///
-/// or if the original code was not a typo:
-/// ```rust,ignore
-/// match foo {
-///     Bar | Baz => bar(), // <= shows the intent better
-///     Quz => quz(),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `match` with identical arm bodies.
+    ///
+    /// **Why is this bad?** This is probably a copy & paste error. If arm bodies
+    /// are the same on purpose, you can factor them
+    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
+    ///
+    /// **Known problems:** False positive possible with order dependent `match`
+    /// (see issue
+    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// match foo {
+    ///     Bar => bar(),
+    ///     Quz => quz(),
+    ///     Baz => bar(), // <= oops
+    /// }
+    /// ```
+    ///
+    /// This should probably be
+    /// ```rust,ignore
+    /// match foo {
+    ///     Bar => bar(),
+    ///     Quz => quz(),
+    ///     Baz => baz(), // <= fixed
+    /// }
+    /// ```
+    ///
+    /// or if the original code was not a typo:
+    /// ```rust,ignore
+    /// match foo {
+    ///     Bar | Baz => bar(), // <= shows the intent better
+    ///     Quz => quz(),
+    /// }
+    /// ```
     pub MATCH_SAME_ARMS,
     pedantic,
     "`match` with identical arm bodies"
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct CopyAndPaste;
-
-impl LintPass for CopyAndPaste {
-    fn get_lints(&self) -> LintArray {
-        lint_array![IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]
-    }
-}
+declare_lint_pass!(CopyAndPaste => [IFS_SAME_COND, IF_SAME_THEN_ELSE, MATCH_SAME_ARMS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyAndPaste {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if !in_macro(expr.span) {
+        if !in_macro_or_desugar(expr.span) {
             // skip ifs directly in else, it will be checked in the parent if
-            if let Some(&Expr {
-                node: ExprKind::If(_, _, Some(ref else_expr)),
-                ..
-            }) = get_parent_expr(cx, expr)
-            {
-                if else_expr.id == expr.id {
-                    return;
+            if let Some(expr) = get_parent_expr(cx, expr) {
+                if let Some((_, _, Some(ref else_expr))) = higher::if_block(&expr) {
+                    if else_expr.hir_id == expr.hir_id {
+                        return;
+                    }
                 }
             }
 
@@ -157,7 +149,8 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
         h.finish()
     };
 
-    let eq: &dyn Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
+    let eq: &dyn Fn(&&Expr, &&Expr) -> bool =
+        &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
 
     if let Some((i, j)) = search_same(conds, hash, eq) {
         span_note_and_lint(
@@ -201,7 +194,8 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
                 |db| {
                     db.span_note(i.body.span, "same as this");
 
-                    // Note: this does not use `span_suggestion` on purpose: there is no clean way
+                    // Note: this does not use `span_suggestion` on purpose:
+                    // there is no clean way
                     // to remove the other arm. Building a span and suggest to replace it to ""
                     // makes an even more confusing error message. Also in order not to make up a
                     // span for the whole pattern, the suggestion is only shown when there is only
@@ -217,7 +211,10 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
                             // hiding all the subsequent arms, and rust won't compile
                             db.span_note(
                                 i.body.span,
-                                &format!("`{}` has the same arm body as the `_` wildcard, consider removing it`", lhs),
+                                &format!(
+                                    "`{}` has the same arm body as the `_` wildcard, consider removing it`",
+                                    lhs
+                                ),
                             );
                         } else {
                             db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
@@ -229,15 +226,15 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
     }
 }
 
-/// Return the list of condition expressions and the list of blocks in a
+/// Returns the list of condition expressions and the list of blocks in a
 /// sequence of `if/else`.
-/// Eg. would return `([a, b], [c, d, e])` for the expression
+/// E.g., this returns `([a, b], [c, d, e])` for the expression
 /// `if a { c } else if b { d } else { e }`.
-fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) {
-    let mut conds = SmallVector::new();
-    let mut blocks: SmallVector<&Block> = SmallVector::new();
+fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>) {
+    let mut conds = SmallVec::new();
+    let mut blocks: SmallVec<[&Block; 1]> = SmallVec::new();
 
-    while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.node {
+    while let Some((ref cond, ref then_expr, ref else_expr)) = higher::if_block(&expr) {
         conds.push(&**cond);
         if let ExprKind::Block(ref block, _) = then_expr.node {
             blocks.push(block);
@@ -262,15 +259,21 @@ fn if_sequence(mut expr: &Expr) -> (SmallVector<&Expr>, SmallVector<&Block>) {
     (conds, blocks)
 }
 
-/// Return the list of bindings in a pattern.
-fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> HashMap<LocalInternedString, Ty<'tcx>> {
-    fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut HashMap<LocalInternedString, Ty<'tcx>>) {
+/// Returns the list of bindings in a pattern.
+fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalInternedString, Ty<'tcx>> {
+    fn bindings_impl<'a, 'tcx>(
+        cx: &LateContext<'a, 'tcx>,
+        pat: &Pat,
+        map: &mut FxHashMap<LocalInternedString, Ty<'tcx>>,
+    ) {
         match pat.node {
             PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
-            PatKind::TupleStruct(_, ref pats, _) => for pat in pats {
-                bindings_impl(cx, pat, map);
+            PatKind::TupleStruct(_, ref pats, _) => {
+                for pat in pats {
+                    bindings_impl(cx, pat, map);
+                }
             },
-            PatKind::Binding(_, _, ident, ref as_pat) => {
+            PatKind::Binding(.., ident, ref as_pat) => {
                 if let Entry::Vacant(v) = map.entry(ident.as_str()) {
                     v.insert(cx.tables.pat_ty(pat));
                 }
@@ -278,11 +281,15 @@ fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut Hash
                     bindings_impl(cx, as_pat, map);
                 }
             },
-            PatKind::Struct(_, ref fields, _) => for pat in fields {
-                bindings_impl(cx, &pat.node.pat, map);
+            PatKind::Struct(_, ref fields, _) => {
+                for pat in fields {
+                    bindings_impl(cx, &pat.node.pat, map);
+                }
             },
-            PatKind::Tuple(ref fields, _) => for pat in fields {
-                bindings_impl(cx, pat, map);
+            PatKind::Tuple(ref fields, _) => {
+                for pat in fields {
+                    bindings_impl(cx, pat, map);
+                }
             },
             PatKind::Slice(ref lhs, ref mid, ref rhs) => {
                 for pat in lhs {
@@ -299,12 +306,11 @@ fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut Hash
         }
     }
 
-    let mut result = HashMap::new();
+    let mut result = FxHashMap::default();
     bindings_impl(cx, pat, &mut result);
     result
 }
 
-
 fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
 where
     Eq: Fn(&T, &T) -> bool,
@@ -333,7 +339,8 @@ fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Option<(&T, &T)>
         };
     }
 
-    let mut map: HashMap<_, Vec<&_>> = HashMap::with_capacity(exprs.len());
+    let mut map: FxHashMap<_, Vec<&_>> =
+        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 
     for expr in exprs {
         match map.entry(hash(expr)) {
diff --git a/clippy_lints/src/copy_iterator.rs b/clippy_lints/src/copy_iterator.rs
new file mode 100644 (file)
index 0000000..fe24ff1
--- /dev/null
@@ -0,0 +1,51 @@
+use crate::utils::{is_copy, match_path, paths, span_note_and_lint};
+use rustc::hir::{Item, ItemKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for types that implement `Copy` as well as
+    /// `Iterator`.
+    ///
+    /// **Why is this bad?** Implicit copies can be confusing when working with
+    /// iterator combinators.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// #[derive(Copy, Clone)]
+    /// struct Countdown(u8);
+    ///
+    /// impl Iterator for Countdown {
+    ///     // ...
+    /// }
+    ///
+    /// let a: Vec<_> = my_iterator.take(1).collect();
+    /// let b: Vec<_> = my_iterator.collect();
+    /// ```
+    pub COPY_ITERATOR,
+    pedantic,
+    "implementing `Iterator` on a `Copy` type"
+}
+
+declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyIterator {
+    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
+        if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.node {
+            let ty = cx.tcx.type_of(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id));
+
+            if is_copy(cx, ty) && match_path(&trait_ref.path, &*paths::ITERATOR) {
+                span_note_and_lint(
+                    cx,
+                    COPY_ITERATOR,
+                    item.span,
+                    "you are implementing `Iterator` on a `Copy` type",
+                    item.span,
+                    "consider implementing `IntoIterator` instead",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/cyclomatic_complexity.rs b/clippy_lints/src/cyclomatic_complexity.rs
deleted file mode 100644 (file)
index d66e6f2..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-//! calculate cyclomatic complexity and warn about overly complex functions
-
-use rustc::cfg::CFG;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
-use rustc::ty;
-use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use syntax::ast::{Attribute, NodeId};
-use syntax::codemap::Span;
-
-use crate::utils::{in_macro, is_allowed, match_type, paths, span_help_and_lint, LimitStack};
-
-/// **What it does:** Checks for methods with high cyclomatic complexity.
-///
-/// **Why is this bad?** Methods of high cyclomatic complexity tend to be badly
-/// readable. Also LLVM will usually optimize small methods better.
-///
-/// **Known problems:** Sometimes it's hard to find a way to reduce the
-/// complexity.
-///
-/// **Example:** No. You'll see it when you get the warning.
-declare_clippy_lint! {
-    pub CYCLOMATIC_COMPLEXITY,
-    complexity,
-    "functions that should be split up into multiple functions"
-}
-
-pub struct CyclomaticComplexity {
-    limit: LimitStack,
-}
-
-impl CyclomaticComplexity {
-    pub fn new(limit: u64) -> Self {
-        Self {
-            limit: LimitStack::new(limit),
-        }
-    }
-}
-
-impl LintPass for CyclomaticComplexity {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(CYCLOMATIC_COMPLEXITY)
-    }
-}
-
-impl CyclomaticComplexity {
-    fn check<'a, 'tcx: 'a>(&mut self, cx: &'a LateContext<'a, 'tcx>, body: &'tcx Body, span: Span) {
-        if in_macro(span) {
-            return;
-        }
-
-        let cfg = CFG::new(cx.tcx, body);
-        let expr = &body.value;
-        let n = cfg.graph.len_nodes() as u64;
-        let e = cfg.graph.len_edges() as u64;
-        if e + 2 < n {
-            // the function has unreachable code, other lints should catch this
-            return;
-        }
-        let cc = e + 2 - n;
-        let mut helper = CCHelper {
-            match_arms: 0,
-            divergence: 0,
-            short_circuits: 0,
-            returns: 0,
-            cx,
-        };
-        helper.visit_expr(expr);
-        let CCHelper {
-            match_arms,
-            divergence,
-            short_circuits,
-            returns,
-            ..
-        } = helper;
-        let ret_ty = cx.tables.node_id_to_type(expr.hir_id);
-        let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) {
-            returns
-        } else {
-            returns / 2
-        };
-
-        if cc + divergence < match_arms + short_circuits {
-            report_cc_bug(
-                cx,
-                cc,
-                match_arms,
-                divergence,
-                short_circuits,
-                ret_adjust,
-                span,
-                body.id().node_id,
-            );
-        } else {
-            let mut rust_cc = cc + divergence - match_arms - short_circuits;
-            // prevent degenerate cases where unreachable code contains `return` statements
-            if rust_cc >= ret_adjust {
-                rust_cc -= ret_adjust;
-            }
-            if rust_cc > self.limit.limit() {
-                span_help_and_lint(
-                    cx,
-                    CYCLOMATIC_COMPLEXITY,
-                    span,
-                    &format!("the function has a cyclomatic complexity of {}", rust_cc),
-                    "you could split it up into multiple smaller functions",
-                );
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'a, 'tcx>,
-        _: intravisit::FnKind<'tcx>,
-        _: &'tcx FnDecl,
-        body: &'tcx Body,
-        span: Span,
-        node_id: NodeId,
-    ) {
-        let def_id = cx.tcx.hir.local_def_id(node_id);
-        if !cx.tcx.has_attr(def_id, "test") {
-            self.check(cx, body, span);
-        }
-    }
-
-    fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
-        self.limit
-            .push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
-    }
-    fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
-        self.limit
-            .pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
-    }
-}
-
-struct CCHelper<'a, 'tcx: 'a> {
-    match_arms: u64,
-    divergence: u64,
-    returns: u64,
-    short_circuits: u64, // && and ||
-    cx: &'a LateContext<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
-    fn visit_expr(&mut self, e: &'tcx Expr) {
-        match e.node {
-            ExprKind::Match(_, ref arms, _) => {
-                walk_expr(self, e);
-                let arms_n: u64 = arms.iter().map(|arm| arm.pats.len() as u64).sum();
-                if arms_n > 1 {
-                    self.match_arms += arms_n - 2;
-                }
-            },
-            ExprKind::Call(ref callee, _) => {
-                walk_expr(self, e);
-                let ty = self.cx.tables.node_id_to_type(callee.hir_id);
-                match ty.sty {
-                    ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-                        let sig = ty.fn_sig(self.cx.tcx);
-                        if sig.skip_binder().output().sty == ty::TyNever {
-                            self.divergence += 1;
-                        }
-                    },
-                    _ => (),
-                }
-            },
-            ExprKind::Closure(.., _) => (),
-            ExprKind::Binary(op, _, _) => {
-                walk_expr(self, e);
-                match op.node {
-                    BinOpKind::And | BinOpKind::Or => self.short_circuits += 1,
-                    _ => (),
-                }
-            },
-            ExprKind::Ret(_) => self.returns += 1,
-            _ => walk_expr(self, e),
-        }
-    }
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-}
-
-#[cfg(feature = "debugging")]
-#[allow(too_many_arguments)]
-fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, _: NodeId) {
-    span_bug!(
-        span,
-        "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
-         div = {}, shorts = {}, returns = {}. Please file a bug report.",
-        cc,
-        narms,
-        div,
-        shorts,
-        returns
-    );
-}
-#[cfg(not(feature = "debugging"))]
-#[allow(too_many_arguments)]
-fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, id: NodeId) {
-    if !is_allowed(cx, CYCLOMATIC_COMPLEXITY, id) {
-        cx.sess().span_note_without_error(
-            span,
-            &format!(
-                "Clippy encountered a bug calculating cyclomatic complexity \
-                 (hide this message with `#[allow(cyclomatic_complexity)]`): \
-                 cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \
-                 Please file a bug report.",
-                cc,
-                narms,
-                div,
-                shorts,
-                returns
-            ),
-        );
-    }
-}
diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
new file mode 100644 (file)
index 0000000..637e19b
--- /dev/null
@@ -0,0 +1,68 @@
+use crate::utils::sym;
+use crate::utils::{snippet_opt, span_help_and_lint, span_lint_and_sugg};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast;
+use syntax::source_map::Span;
+use syntax::tokenstream::TokenStream;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of dbg!() macro.
+    ///
+    /// **Why is this bad?** `dbg!` macro is intended as a debugging tool. It
+    /// should not be in version control.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// // Bad
+    /// dbg!(true)
+    ///
+    /// // Good
+    /// true
+    /// ```
+    pub DBG_MACRO,
+    restriction,
+    "`dbg!` macro is intended as a debugging tool"
+}
+
+declare_lint_pass!(DbgMacro => [DBG_MACRO]);
+
+impl EarlyLintPass for DbgMacro {
+    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) {
+        if mac.node.path == *sym::dbg {
+            if let Some(sugg) = tts_span(mac.node.tts.clone()).and_then(|span| snippet_opt(cx, span)) {
+                span_lint_and_sugg(
+                    cx,
+                    DBG_MACRO,
+                    mac.span,
+                    "`dbg!` macro is intended as a debugging tool",
+                    "ensure to avoid having uses of it in version control",
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                span_help_and_lint(
+                    cx,
+                    DBG_MACRO,
+                    mac.span,
+                    "`dbg!` macro is intended as a debugging tool",
+                    "ensure to avoid having uses of it in version control",
+                );
+            }
+        }
+    }
+}
+
+// Get span enclosing entire the token stream.
+fn tts_span(tts: TokenStream) -> Option<Span> {
+    let mut cursor = tts.into_trees();
+    let first = cursor.next()?.span();
+    let span = match cursor.last() {
+        Some(tree) => first.to(tree.span()),
+        None => first,
+    };
+    Some(span)
+}
index 4078237e8aa8453ac9f1d65907d5e8fe8f207a80..ba1312add7464f64d52c760ebc43c3171e57ca66 100644 (file)
@@ -1,57 +1,61 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
-use rustc::ty::TypeVariants;
-
-use crate::utils::{any_parent_is_automatically_derived, match_def_path, opt_def_id, paths, span_lint_and_sugg};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 
+use crate::utils::{any_parent_is_automatically_derived, match_def_path, paths, span_lint_and_sugg};
 
-/// **What it does:** Checks for literal calls to `Default::default()`.
-///
-/// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
-/// being gotten than the generic `Default`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// // Bad
-/// let s: String = Default::default();
-///
-/// // Good
-/// let s = String::default();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for literal calls to `Default::default()`.
+    ///
+    /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is
+    /// being gotten than the generic `Default`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// let s: String = Default::default();
+    ///
+    /// // Good
+    /// let s = String::default();
+    /// ```
     pub DEFAULT_TRAIT_ACCESS,
     pedantic,
     "checks for literal calls to Default::default()"
 }
 
-#[derive(Copy, Clone)]
-pub struct DefaultTraitAccess;
-
-impl LintPass for DefaultTraitAccess {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DEFAULT_TRAIT_ACCESS)
-    }
-}
+declare_lint_pass!(DefaultTraitAccess => [DEFAULT_TRAIT_ACCESS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DefaultTraitAccess {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
             if let ExprKind::Call(ref path, ..) = expr.node;
-            if !any_parent_is_automatically_derived(cx.tcx, expr.id);
+            if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
             if let ExprKind::Path(ref qpath) = path.node;
-            if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
-            if match_def_path(cx.tcx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &*paths::DEFAULT_TRAIT_METHOD);
             then {
                 match qpath {
                     QPath::Resolved(..) => {
+                        if_chain! {
+                            // Detect and ignore <Foo as Default>::default() because these calls do
+                            // explicitly name the type.
+                            if let ExprKind::Call(ref method, ref _args) = expr.node;
+                            if let ExprKind::Path(ref p) = method.node;
+                            if let QPath::Resolved(Some(_ty), _path) = p;
+                            then {
+                                return;
+                            }
+                        }
+
                         // TODO: Work out a way to put "whatever the imported way of referencing
                         // this type in this file" rather than a fully-qualified type.
                         let expr_ty = cx.tables.expr_ty(expr);
-                        if let TypeVariants::TyAdt(..) = expr_ty.sty {
+                        if let ty::Adt(..) = expr_ty.sty {
                             let replacement = format!("{}::default()", expr_ty);
                             span_lint_and_sugg(
                                 cx,
@@ -59,12 +63,14 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                                 expr.span,
                                 &format!("Calling {} is more clear than this expression", replacement),
                                 "try",
-                                replacement);
+                                replacement,
+                                Applicability::Unspecified, // First resolve the TODO above
+                            );
                          }
                     },
                     QPath::TypeRelative(..) => {},
                 }
             }
-         }
+        }
     }
 }
index 1edeb30560ce035f7e76331b3c7b224d1a1f9533..62cef778917b984083d1c69f7bda6ca6db06a770 100644 (file)
@@ -6,7 +6,7 @@ macro_rules! declare_deprecated_lint {
 
 /// **What it does:** Nothing. This lint has been deprecated.
 ///
-/// **Deprecation reason:** This used to check for `assert!(a == b)` and recommend 
+/// **Deprecation reason:** This used to check for `assert!(a == b)` and recommend
 /// replacement with `assert_eq!(a, b)`, but this is no longer needed after RFC 2011.
 declare_deprecated_lint! {
     pub SHOULD_ASSERT_EQ,
@@ -82,3 +82,34 @@ macro_rules! declare_deprecated_lint {
     pub MISALIGNED_TRANSMUTE,
     "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr"
 }
+
+/// **What it does:** Nothing. This lint has been deprecated.
+///
+/// **Deprecation reason:** This lint is too subjective, not having a good reason for being in clippy.
+/// Additionally, compound assignment operators may be overloaded separately from their non-assigning
+/// counterparts, so this lint may suggest a change in behavior or the code may not compile.
+declare_deprecated_lint! {
+    pub ASSIGN_OPS,
+    "using compound assignment operators (e.g., `+=`) is harmless"
+}
+
+/// **What it does:** Nothing. This lint has been deprecated.
+///
+/// **Deprecation reason:** The original rule will only lint for `if let`. After
+/// making it support to lint `match`, naming as `if let` is not suitable for it.
+/// So, this lint is deprecated.
+declare_deprecated_lint! {
+    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
+    "this lint has been changed to redundant_pattern_matching"
+}
+
+/// **What it does:** Nothing. This lint has been deprecated.
+///
+/// **Deprecation reason:** This lint used to suggest replacing `let mut vec =
+/// Vec::with_capacity(n); vec.set_len(n);` with `let vec = vec![0; n];`. The
+/// replacement has very different performance characteristics so the lint is
+/// deprecated.
+declare_deprecated_lint! {
+    pub UNSAFE_VECTOR_INITIALIZATION,
+    "the replacement suggested by this lint had substantially different behavior"
+}
index 0689ef25c20715c0fbb8179c05efb6a1070afe94..66bf1a3566fa0400ae7e910f4e2480a4a6ae1507 100644 (file)
@@ -1,79 +1,73 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use rustc::ty::{self, Ty};
-use rustc::hir::*;
-use syntax::codemap::Span;
 use crate::utils::paths;
 use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then};
+use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
-/// explicitly or vice versa.
-///
-/// **Why is this bad?** The implementation of these traits must agree (for
-/// example for use with `HashMap`) so it’s probably a bad idea to use a
-/// default-generated `Hash` implementation with an explicitly defined
-/// `PartialEq`. In particular, the following must hold for any type:
-///
-/// ```rust
-/// k1 == k2 ⇒ hash(k1) == hash(k2)
-/// ```
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// #[derive(Hash)]
-/// struct Foo;
-///
-/// impl PartialEq for Foo {
-///     ...
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
+    /// explicitly or vice versa.
+    ///
+    /// **Why is this bad?** The implementation of these traits must agree (for
+    /// example for use with `HashMap`) so it’s probably a bad idea to use a
+    /// default-generated `Hash` implementation with an explicitly defined
+    /// `PartialEq`. In particular, the following must hold for any type:
+    ///
+    /// ```text
+    /// k1 == k2 ⇒ hash(k1) == hash(k2)
+    /// ```
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// #[derive(Hash)]
+    /// struct Foo;
+    ///
+    /// impl PartialEq for Foo {
+    ///     ...
+    /// }
+    /// ```
     pub DERIVE_HASH_XOR_EQ,
     correctness,
     "deriving `Hash` but implementing `PartialEq` explicitly"
 }
 
-/// **What it does:** Checks for explicit `Clone` implementations for `Copy`
-/// types.
-///
-/// **Why is this bad?** To avoid surprising behaviour, these traits should
-/// agree and the behaviour of `Copy` cannot be overridden. In almost all
-/// situations a `Copy` type should have a `Clone` implementation that does
-/// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
-/// gets you.
-///
-/// **Known problems:** Bounds of generic types are sometimes wrong: https://github.com/rust-lang/rust/issues/26925
-///
-/// **Example:**
-/// ```rust
-/// #[derive(Copy)]
-/// struct Foo;
-///
-/// impl Clone for Foo {
-///     ..
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for explicit `Clone` implementations for `Copy`
+    /// types.
+    ///
+    /// **Why is this bad?** To avoid surprising behaviour, these traits should
+    /// agree and the behaviour of `Copy` cannot be overridden. In almost all
+    /// situations a `Copy` type should have a `Clone` implementation that does
+    /// nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
+    /// gets you.
+    ///
+    /// **Known problems:** Bounds of generic types are sometimes wrong: https://github.com/rust-lang/rust/issues/26925
+    ///
+    /// **Example:**
+    /// ```rust
+    /// #[derive(Copy)]
+    /// struct Foo;
+    ///
+    /// impl Clone for Foo {
+    ///     ..
+    /// }
+    /// ```
     pub EXPL_IMPL_CLONE_ON_COPY,
     pedantic,
     "implementing `Clone` explicitly on `Copy` types"
 }
 
-pub struct Derive;
-
-impl LintPass for Derive {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ)
-    }
-}
+declare_lint_pass!(Derive => [EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.node {
-            let ty = cx.tcx.type_of(cx.tcx.hir.local_def_id(item.id));
+            let ty = cx.tcx.type_of(cx.tcx.hir().local_def_id_from_hir_id(item.hir_id));
             let is_automatically_derived = is_automatically_derived(&*item.attrs);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -94,7 +88,7 @@ fn check_hash_peq<'a, 'tcx>(
     hash_is_automatically_derived: bool,
 ) {
     if_chain! {
-        if match_path(&trait_ref.path, &paths::HASH);
+        if match_path(&trait_ref.path, &*paths::HASH);
         if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait();
         then {
             // Look for the PartialEq implementations for `ty`
@@ -120,9 +114,9 @@ fn check_hash_peq<'a, 'tcx>(
                         cx, DERIVE_HASH_XOR_EQ, span,
                         mess,
                         |db| {
-                        if let Some(node_id) = cx.tcx.hir.as_local_node_id(impl_id) {
+                        if let Some(node_id) = cx.tcx.hir().as_local_node_id(impl_id) {
                             db.span_note(
-                                cx.tcx.hir.span(node_id),
+                                cx.tcx.hir().span(node_id),
                                 "`PartialEq` implemented here"
                             );
                         }
@@ -135,27 +129,29 @@ fn check_hash_peq<'a, 'tcx>(
 
 /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
 fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref: &TraitRef, ty: Ty<'tcx>) {
-    if match_path(&trait_ref.path, &paths::CLONE_TRAIT) {
+    if match_path(&trait_ref.path, &*paths::CLONE_TRAIT) {
         if !is_copy(cx, ty) {
             return;
         }
 
         match ty.sty {
-            ty::TyAdt(def, _) if def.is_union() => return,
+            ty::Adt(def, _) if def.is_union() => return,
 
             // Some types are not Clone by default but could be cloned “by hand” if necessary
-            ty::TyAdt(def, substs) => for variant in &def.variants {
-                for field in &variant.fields {
-                    if let ty::TyFnDef(..) = field.ty(cx.tcx, substs).sty {
-                        return;
-                    }
-                }
-                for subst in substs {
-                    if let ty::subst::UnpackedKind::Type(subst) = subst.unpack() {
-                        if let ty::TyParam(_) = subst.sty {
+            ty::Adt(def, substs) => {
+                for variant in &def.variants {
+                    for field in &variant.fields {
+                        if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty {
                             return;
                         }
                     }
+                    for subst in substs {
+                        if let ty::subst::UnpackedKind::Type(subst) = subst.unpack() {
+                            if let ty::Param(_) = subst.sty {
+                                return;
+                            }
+                        }
+                    }
                 }
             },
             _ => (),
index 2b11e8fa77d4d6c399d7c92e1cfba61bf2d96234..f55cf7246b4e31e2182f64a1fbfc7ab6f547f2af 100644 (file)
@@ -1,57 +1,55 @@
+use crate::utils::span_lint;
+use crate::utils::sym;
 use itertools::Itertools;
 use pulldown_cmark;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_data_structures::fx::FxHashSet;
+use std::ops::Range;
 use syntax::ast;
-use syntax::codemap::{BytePos, Span};
+use syntax::source_map::{BytePos, Span};
 use syntax_pos::Pos;
-use crate::utils::span_lint;
 use url::Url;
 
-/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
-/// outside ticks in documentation.
-///
-/// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and
-/// camel-case probably indicates some code which should be included between
-/// ticks. `_` can also be used for emphasis in markdown, this lint tries to
-/// consider that.
-///
-/// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks
-/// for is limited, and there are still false positives.
-///
-/// **Examples:**
-/// ```rust
-/// /// Do something with the foo_bar parameter. See also
-/// /// that::other::module::foo.
-/// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
-/// fn doit(foo_bar) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for the presence of `_`, `::` or camel-case words
+    /// outside ticks in documentation.
+    ///
+    /// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and
+    /// camel-case probably indicates some code which should be included between
+    /// ticks. `_` can also be used for emphasis in markdown, this lint tries to
+    /// consider that.
+    ///
+    /// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks
+    /// for is limited, and there are still false positives.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// /// Do something with the foo_bar parameter. See also
+    /// /// that::other::module::foo.
+    /// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
+    /// fn doit(foo_bar) { .. }
+    /// ```
     pub DOC_MARKDOWN,
     pedantic,
     "presence of `_`, `::` or camel-case outside backticks in documentation"
 }
 
+#[allow(clippy::module_name_repetitions)]
 #[derive(Clone)]
-pub struct Doc {
-    valid_idents: Vec<String>,
+pub struct DocMarkdown {
+    valid_idents: FxHashSet<String>,
 }
 
-impl Doc {
-    pub fn new(valid_idents: Vec<String>) -> Self {
-        Self {
-            valid_idents,
-        }
+impl DocMarkdown {
+    pub fn new(valid_idents: FxHashSet<String>) -> Self {
+        Self { valid_idents }
     }
 }
 
-impl LintPass for Doc {
-    fn get_lints(&self) -> LintArray {
-        lint_array![DOC_MARKDOWN]
-    }
-}
+impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN]);
 
-impl EarlyLintPass for Doc {
+impl EarlyLintPass for DocMarkdown {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
         check_attrs(cx, &self.valid_idents, &krate.attrs);
     }
@@ -61,32 +59,13 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
     }
 }
 
-struct Parser<'a> {
-    parser: pulldown_cmark::Parser<'a>,
-}
-
-impl<'a> Parser<'a> {
-    fn new(parser: pulldown_cmark::Parser<'a>) -> Self {
-        Self { parser }
-    }
-}
-
-impl<'a> Iterator for Parser<'a> {
-    type Item = (usize, pulldown_cmark::Event<'a>);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let offset = self.parser.get_offset();
-        self.parser.next().map(|event| (offset, event))
-    }
-}
-
 /// Cleanup documentation decoration (`///` and such).
 ///
 /// We can't use `syntax::attr::AttributeMethods::with_desugared_doc` or
 /// `syntax::parse::lexer::comments::strip_doc_comment_decoration` because we
 /// need to keep track of
 /// the spans but this function is inspired from the later.
-#[allow(cast_possible_truncation)]
+#[allow(clippy::cast_possible_truncation)]
 pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) {
     // one-line comments lose their prefix
     const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
@@ -97,9 +76,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
             doc.push('\n');
             return (
                 doc.to_owned(),
-                vec![
-                    (doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32))),
-                ],
+                vec![(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32)))],
             );
         }
     }
@@ -111,7 +88,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
         for line in doc.lines() {
             let offset = line.as_ptr() as usize - comment.as_ptr() as usize;
             debug_assert_eq!(offset as u32 as usize, offset);
-            contains_initial_stars |= line.trim_left().starts_with('*');
+            contains_initial_stars |= line.trim_start().starts_with('*');
             // +1 for the newline
             sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(offset as u32))));
         }
@@ -139,7 +116,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
     panic!("not a doc-comment: {}", comment);
 }
 
-pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &[String], attrs: &'a [ast::Attribute]) {
+pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [ast::Attribute]) {
     let mut doc = String::new();
     let mut spans = vec![];
 
@@ -151,7 +128,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &[String], attrs: &'
                 spans.extend_from_slice(&current_spans);
                 doc.push_str(&current);
             }
-        } else if attr.name() == "doc" {
+        } else if attr.check_name(*sym::doc) {
             // ignore mix of sugared and non-sugared doc
             return;
         }
@@ -165,30 +142,31 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &[String], attrs: &'
     }
 
     if !doc.is_empty() {
-        let parser = Parser::new(pulldown_cmark::Parser::new(&doc));
-        let parser = parser.coalesce(|x, y| {
+        let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter();
+        // Iterate over all `Events` and combine consecutive events into one
+        let events = parser.coalesce(|previous, current| {
             use pulldown_cmark::Event::*;
 
-            let x_offset = x.0;
-            let y_offset = y.0;
+            let previous_range = previous.1;
+            let current_range = current.1;
 
-            match (x.1, y.1) {
-                (Text(x), Text(y)) => {
-                    let mut x = x.into_owned();
-                    x.push_str(&y);
-                    Ok((x_offset, Text(x.into())))
+            match (previous.0, current.0) {
+                (Text(previous), Text(current)) => {
+                    let mut previous = previous.to_string();
+                    previous.push_str(&current);
+                    Ok((Text(previous.into()), previous_range))
                 },
-                (x, y) => Err(((x_offset, x), (y_offset, y))),
+                (previous, current) => Err(((previous, previous_range), (current, current_range))),
             }
         });
-        check_doc(cx, valid_idents, parser, &spans);
+        check_doc(cx, valid_idents, events, &spans);
     }
 }
 
-fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
+fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
     cx: &EarlyContext<'_>,
-    valid_idents: &[String],
-    docs: Events,
+    valid_idents: &FxHashSet<String>,
+    events: Events,
     spans: &[(usize, Span)],
 ) {
     use pulldown_cmark::Event::*;
@@ -197,15 +175,15 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
     let mut in_code = false;
     let mut in_link = None;
 
-    for (offset, event) in docs {
+    for (event, range) in events {
         match event {
-            Start(CodeBlock(_)) | Start(Code) => in_code = true,
-            End(CodeBlock(_)) | End(Code) => in_code = false,
-            Start(Link(link, _)) => in_link = Some(link),
-            End(Link(_, _)) => in_link = None,
+            Start(CodeBlock(_)) => in_code = true,
+            End(CodeBlock(_)) => in_code = false,
+            Start(Link(_, url, _)) => in_link = Some(url),
+            End(Link(..)) => in_link = None,
             Start(_tag) | End(_tag) => (),         // We don't care about other tags
             Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it
-            SoftBreak | HardBreak => (),
+            SoftBreak | HardBreak | TaskListMarker(_) | Code(_) => (),
             FootnoteReference(text) | Text(text) => {
                 if Some(&text) == in_link.as_ref() {
                     // Probably a link of the form `<http://example.com>`
@@ -215,7 +193,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
                 }
 
                 if !in_code {
-                    let index = match spans.binary_search_by(|c| c.0.cmp(&offset)) {
+                    let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) {
                         Ok(o) => o,
                         Err(e) => e - 1,
                     };
@@ -223,7 +201,7 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
                     let (begin, span) = spans[index];
 
                     // Adjust for the beginning of the current `Event`
-                    let span = span.with_lo(span.lo() + BytePos::from_usize(offset - begin));
+                    let span = span.with_lo(span.lo() + BytePos::from_usize(range.start - begin));
 
                     check_text(cx, valid_idents, &text, span);
                 }
@@ -232,14 +210,14 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
     }
 }
 
-fn check_text(cx: &EarlyContext<'_>, valid_idents: &[String], text: &str, span: Span) {
-    for word in text.split_whitespace() {
+fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
+    for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
         // Trim punctuation as in `some comment (see foo::bar).`
         //                                                   ^^
         // Or even as in `_foo bar_` which is emphasized.
         let word = word.trim_matches(|c: char| !c.is_alphanumeric());
 
-        if valid_idents.iter().any(|i| i == word) {
+        if valid_idents.contains(word) {
             continue;
         }
 
@@ -256,22 +234,18 @@ fn check_text(cx: &EarlyContext<'_>, valid_idents: &[String], text: &str, span:
 }
 
 fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) {
-    /// Checks if a string is camel-case, ie. contains at least two uppercase
-    /// letter (`Clippy` is
-    /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded
-    /// (`IDs` is ok).
+    /// Checks if a string is camel-case, i.e., contains at least two uppercase
+    /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
+    /// Plurals are also excluded (`IDs` is ok).
     fn is_camel_case(s: &str) -> bool {
         if s.starts_with(|c: char| c.is_digit(10)) {
             return false;
         }
 
-        let s = if s.ends_with('s') {
-            &s[..s.len() - 1]
-        } else {
-            s
-        };
+        let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s };
 
-        s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
+        s.chars().all(char::is_alphanumeric)
+            && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
             && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
     }
 
@@ -279,6 +253,10 @@ fn has_underscore(s: &str) -> bool {
         s != "_" && !s.contains("\\_") && s.contains('_')
     }
 
+    fn has_hyphen(s: &str) -> bool {
+        s != "-" && s.contains('-')
+    }
+
     if let Ok(url) = Url::parse(word) {
         // try to get around the fact that `foo::bar` parses as a valid URL
         if !url.cannot_be_a_base() {
@@ -293,6 +271,11 @@ fn has_underscore(s: &str) -> bool {
         }
     }
 
+    // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
+    if has_underscore(word) && has_hyphen(word) {
+        return;
+    }
+
     if has_underscore(word) || word.contains("::") || is_camel_case(word) {
         span_lint(
             cx,
index 434ccb69921e7d916275350c8019706b3a076dcc..d64939d01298cd0769aa3356488843321e467d30 100644 (file)
@@ -1,56 +1,45 @@
 //! Lint on unnecessary double comparisons. Some examples:
 
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::codemap::Span;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::source_map::Span;
 
-use crate::utils::{snippet, span_lint_and_sugg, SpanlessEq};
+use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
 
-/// **What it does:** Checks for double comparions that could be simpified to a single expression.
-///
-///
-/// **Why is this bad?** Readability.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x == y || x < y
-/// ```
-///
-/// Could be written as:
-///
-/// ```rust
-/// x <= y
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for double comparions that could be simplified to a single expression.
+    ///
+    ///
+    /// **Why is this bad?** Readability.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x == y || x < y
+    /// ```
+    ///
+    /// Could be written as:
+    ///
+    /// ```rust
+    /// x <= y
+    /// ```
     pub DOUBLE_COMPARISONS,
     complexity,
     "unnecessary double comparisons that can be simplified"
 }
 
-pub struct DoubleComparisonPass;
+declare_lint_pass!(DoubleComparisons => [DOUBLE_COMPARISONS]);
 
-impl LintPass for DoubleComparisonPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DOUBLE_COMPARISONS)
-    }
-}
-
-impl<'a, 'tcx> DoubleComparisonPass {
-    fn check_binop(
-        &self,
-        cx: &LateContext<'a, 'tcx>,
-        op: BinOpKind,
-        lhs: &'tcx Expr,
-        rhs: &'tcx Expr,
-        span: Span,
-    ) {
+impl<'a, 'tcx> DoubleComparisons {
+    #[allow(clippy::similar_names)]
+    fn check_binop(self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) {
         let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) {
             (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
                 (lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
-            }
+            },
             _ => return,
         };
         let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
@@ -59,25 +48,40 @@ fn check_binop(
         }
         macro_rules! lint_double_comparison {
             ($op:tt) => {{
-                let lhs_str = snippet(cx, llhs.span, "");
-                let rhs_str = snippet(cx, lrhs.span, "");
+                let mut applicability = Applicability::MachineApplicable;
+                let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability);
+                let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability);
                 let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
-                span_lint_and_sugg(cx, DOUBLE_COMPARISONS, span,
-                                   "This binary expression can be simplified",
-                                   "try", sugg);
-            }}
+                span_lint_and_sugg(
+                    cx,
+                    DOUBLE_COMPARISONS,
+                    span,
+                    "This binary expression can be simplified",
+                    "try",
+                    sugg,
+                    applicability,
+                );
+            }};
         }
         match (op, lkind, rkind) {
-            (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => lint_double_comparison!(<=),
-            (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => lint_double_comparison!(>=),
-            (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => lint_double_comparison!(!=),
-            (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => lint_double_comparison!(==),
+            (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
+                lint_double_comparison!(<=)
+            },
+            (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
+                lint_double_comparison!(>=)
+            },
+            (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
+                lint_double_comparison!(!=)
+            },
+            (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
+                lint_double_comparison!(==)
+            },
             _ => (),
         };
     }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DoubleComparisonPass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DoubleComparisons {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = expr.node {
             self.check_binop(cx, kind.node, lhs, rhs, expr.span);
index abd5666385d029dbc710eaffb8e3f092842b6710..f39ea6a3cc5a36d8e48a0a3dcd7b17ff5533ca26 100644 (file)
@@ -1,54 +1,71 @@
+use crate::utils::{in_macro_or_desugar, span_lint};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::*;
-use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
-use rustc::{declare_lint, lint_array};
 
-/// **What it does:** Checks for unnecessary double parentheses.
-///
-/// **Why is this bad?** This makes code harder to read and might indicate a
-/// mistake.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// ((0))
-/// foo((0))
-/// ((1, 2))
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for unnecessary double parentheses.
+    ///
+    /// **Why is this bad?** This makes code harder to read and might indicate a
+    /// mistake.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// ((0))
+    /// foo((0))
+    /// ((1, 2))
+    /// ```
     pub DOUBLE_PARENS,
     complexity,
     "Warn on unnecessary double parentheses"
 }
 
-#[derive(Copy, Clone)]
-pub struct DoubleParens;
-
-impl LintPass for DoubleParens {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DOUBLE_PARENS)
-    }
-}
+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) {
+            return;
+        }
+
         match expr.node {
             ExprKind::Paren(ref in_paren) => match in_paren.node {
                 ExprKind::Paren(_) | ExprKind::Tup(_) => {
-                    cx.span_lint(DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses");
+                    span_lint(
+                        cx,
+                        DOUBLE_PARENS,
+                        expr.span,
+                        "Consider removing unnecessary double parentheses",
+                    );
                 },
                 _ => {},
             },
-            ExprKind::Call(_, ref params) => if params.len() == 1 {
-                let param = &params[0];
-                if let ExprKind::Paren(_) = param.node {
-                    cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
+            ExprKind::Call(_, ref params) => {
+                if params.len() == 1 {
+                    let param = &params[0];
+                    if let ExprKind::Paren(_) = param.node {
+                        span_lint(
+                            cx,
+                            DOUBLE_PARENS,
+                            param.span,
+                            "Consider removing unnecessary double parentheses",
+                        );
+                    }
                 }
             },
-            ExprKind::MethodCall(_, ref params) => if params.len() == 2 {
-                let param = &params[1];
-                if let ExprKind::Paren(_) = param.node {
-                    cx.span_lint(DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
+            ExprKind::MethodCall(_, ref params) => {
+                if params.len() == 2 {
+                    let param = &params[1];
+                    if let ExprKind::Paren(_) = param.node {
+                        span_lint(
+                            cx,
+                            DOUBLE_PARENS,
+                            param.span,
+                            "Consider removing unnecessary double parentheses",
+                        );
+                    }
                 }
             },
             _ => {},
diff --git a/clippy_lints/src/drop_bounds.rs b/clippy_lints/src/drop_bounds.rs
new file mode 100644 (file)
index 0000000..61009cc
--- /dev/null
@@ -0,0 +1,69 @@
+use crate::utils::{match_def_path, paths, span_lint};
+use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for generics with `std::ops::Drop` as bounds.
+    ///
+    /// **Why is this bad?** `Drop` bounds do not really accomplish anything.
+    /// A type may have compiler-generated drop glue without implementing the
+    /// `Drop` trait itself. The `Drop` trait also only has one method,
+    /// `Drop::drop`, and that function is by fiat not callable in user code.
+    /// So there is really no use case for using `Drop` in trait bounds.
+    ///
+    /// The most likely use case of a drop bound is to distinguish between types
+    /// that have destructors and types that don't. Combined with specialization,
+    /// a naive coder would write an implementation that assumed a type could be
+    /// trivially dropped, then write a specialization for `T: Drop` that actually
+    /// calls the destructor. Except that doing so is not correct; String, for
+    /// example, doesn't actually implement Drop, but because String contains a
+    /// Vec, assuming it can be trivially dropped will leak memory.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo<T: Drop>() {}
+    /// ```
+    pub DROP_BOUNDS,
+    correctness,
+    "Bounds of the form `T: Drop` are useless"
+}
+
+const DROP_BOUNDS_SUMMARY: &str = "Bounds of the form `T: Drop` are useless. \
+                                   Use `std::mem::needs_drop` to detect if a type has drop glue.";
+
+declare_lint_pass!(DropBounds => [DROP_BOUNDS]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropBounds {
+    fn check_generic_param(&mut self, cx: &rustc::lint::LateContext<'a, 'tcx>, p: &'tcx GenericParam) {
+        for bound in &p.bounds {
+            lint_bound(cx, bound);
+        }
+    }
+    fn check_where_predicate(&mut self, cx: &rustc::lint::LateContext<'a, 'tcx>, p: &'tcx WherePredicate) {
+        if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounds, .. }) = p {
+            for bound in bounds {
+                lint_bound(cx, bound);
+            }
+        }
+    }
+}
+
+fn lint_bound<'a, 'tcx>(cx: &rustc::lint::LateContext<'a, 'tcx>, bound: &'tcx GenericBound) {
+    if_chain! {
+        if let GenericBound::Trait(t, _) = bound;
+        if let Some(def_id) = t.trait_ref.path.res.opt_def_id();
+        if match_def_path(cx, def_id, &*paths::DROP_TRAIT);
+        then {
+            span_lint(
+                cx,
+                DROP_BOUNDS,
+                t.span,
+                DROP_BOUNDS_SUMMARY
+            );
+        }
+    }
+}
index 071afde986ad191b90ade8b1a5c4030d9652209e..a6dcb51fcae83a7966b456b9ed7d632503c47f86 100644 (file)
@@ -1,97 +1,97 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{is_copy, match_def_path, paths, span_note_and_lint};
 use if_chain::if_chain;
-use rustc::ty;
 use rustc::hir::*;
-use crate::utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for calls to `std::mem::drop` with a reference
-/// instead of an owned value.
-///
-/// **Why is this bad?** Calling `drop` on a reference will only drop the
-/// reference itself, which is a no-op. It will not call the `drop` method (from
-/// the `Drop` trait implementation) on the underlying referenced value, which
-/// is likely what was intended.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let mut lock_guard = mutex.lock();
-/// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
-/// // still locked
-/// operation_that_requires_mutex_to_be_unlocked();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `std::mem::drop` with a reference
+    /// instead of an owned value.
+    ///
+    /// **Why is this bad?** Calling `drop` on a reference will only drop the
+    /// reference itself, which is a no-op. It will not call the `drop` method (from
+    /// the `Drop` trait implementation) on the underlying referenced value, which
+    /// is likely what was intended.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let mut lock_guard = mutex.lock();
+    /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
+    /// // still locked
+    /// operation_that_requires_mutex_to_be_unlocked();
+    /// ```
     pub DROP_REF,
     correctness,
     "calls to `std::mem::drop` with a reference instead of an owned value"
 }
 
-/// **What it does:** Checks for calls to `std::mem::forget` with a reference
-/// instead of an owned value.
-///
-/// **Why is this bad?** Calling `forget` on a reference will only forget the
-/// reference itself, which is a no-op. It will not forget the underlying
-/// referenced
-/// value, which is likely what was intended.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = Box::new(1);
-/// std::mem::forget(&x) // Should have been forget(x), x will still be dropped
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `std::mem::forget` with a reference
+    /// instead of an owned value.
+    ///
+    /// **Why is this bad?** Calling `forget` on a reference will only forget the
+    /// reference itself, which is a no-op. It will not forget the underlying
+    /// referenced
+    /// value, which is likely what was intended.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = Box::new(1);
+    /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped
+    /// ```
     pub FORGET_REF,
     correctness,
     "calls to `std::mem::forget` with a reference instead of an owned value"
 }
 
-/// **What it does:** Checks for calls to `std::mem::drop` with a value
-/// that derives the Copy trait
-///
-/// **Why is this bad?** Calling `std::mem::drop` [does nothing for types that
-/// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
-/// value will be copied and moved into the function on invocation.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x:i32 = 42;   // i32 implements Copy
-/// std::mem::drop(x) // A copy of x is passed to the function, leaving the
-/// // original unaffected
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `std::mem::drop` with a value
+    /// that derives the Copy trait
+    ///
+    /// **Why is this bad?** Calling `std::mem::drop` [does nothing for types that
+    /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
+    /// value will be copied and moved into the function on invocation.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: i32 = 42; // i32 implements Copy
+    /// std::mem::drop(x) // A copy of x is passed to the function, leaving the
+    ///                   // original unaffected
+    /// ```
     pub DROP_COPY,
     correctness,
     "calls to `std::mem::drop` with a value that implements Copy"
 }
 
-/// **What it does:** Checks for calls to `std::mem::forget` with a value that
-/// derives the Copy trait
-///
-/// **Why is this bad?** Calling `std::mem::forget` [does nothing for types that
-/// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
-/// value will be copied and moved into the function on invocation.
-///
-/// An alternative, but also valid, explanation is that Copy types do not
-/// implement
-/// the Drop trait, which means they have no destructors. Without a destructor,
-/// there
-/// is nothing for `std::mem::forget` to ignore.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x:i32 = 42;     // i32 implements Copy
-/// std::mem::forget(x) // A copy of x is passed to the function, leaving the
-/// // original unaffected
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `std::mem::forget` with a value that
+    /// derives the Copy trait
+    ///
+    /// **Why is this bad?** Calling `std::mem::forget` [does nothing for types that
+    /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
+    /// value will be copied and moved into the function on invocation.
+    ///
+    /// An alternative, but also valid, explanation is that Copy types do not
+    /// implement
+    /// the Drop trait, which means they have no destructors. Without a destructor,
+    /// there
+    /// is nothing for `std::mem::forget` to ignore.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: i32 = 42; // i32 implements Copy
+    /// std::mem::forget(x) // A copy of x is passed to the function, leaving the
+    ///                     // original unaffected
+    /// ```
     pub FORGET_COPY,
     correctness,
     "calls to `std::mem::forget` with a value that implements Copy"
 const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements Copy. \
                                    Forgetting a copy leaves the original intact.";
 
-#[allow(missing_copy_implementations)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY)
-    }
-}
+declare_lint_pass!(DropForgetRef => [DROP_REF, FORGET_REF, DROP_COPY, FORGET_COPY]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropForgetRef {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
             if let ExprKind::Call(ref path, ref args) = expr.node;
             if let ExprKind::Path(ref qpath) = path.node;
             if args.len() == 1;
-            if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
+            if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
             then {
                 let lint;
                 let msg;
                 let arg = &args[0];
                 let arg_ty = cx.tables.expr_ty(arg);
 
-                if let ty::TyRef(..) = arg_ty.sty {
-                    if match_def_path(cx.tcx, def_id, &paths::DROP) {
+                if let ty::Ref(..) = arg_ty.sty {
+                    if match_def_path(cx, def_id, &*paths::DROP) {
                         lint = DROP_REF;
                         msg = DROP_REF_SUMMARY.to_string();
-                    } else if match_def_path(cx.tcx, def_id, &paths::MEM_FORGET) {
+                    } else if match_def_path(cx, def_id, &*paths::MEM_FORGET) {
                         lint = FORGET_REF;
                         msg = FORGET_REF_SUMMARY.to_string();
                     } else {
@@ -145,10 +138,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                                        arg.span,
                                        &format!("argument has type {}", arg_ty));
                 } else if is_copy(cx, arg_ty) {
-                    if match_def_path(cx.tcx, def_id, &paths::DROP) {
+                    if match_def_path(cx, def_id, &*paths::DROP) {
                         lint = DROP_COPY;
                         msg = DROP_COPY_SUMMARY.to_string();
-                    } else if match_def_path(cx.tcx, def_id, &paths::MEM_FORGET) {
+                    } else if match_def_path(cx, def_id, &*paths::MEM_FORGET) {
                         lint = FORGET_COPY;
                         msg = FORGET_COPY_SUMMARY.to_string();
                     } else {
index 517befa7790f9011a735076d6b8422fa839c2c0d..79c9e885891115cd63f07fb65c277b9c93e65cdc 100644 (file)
@@ -1,63 +1,62 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
-use syntax::codemap::Spanned;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::source_map::Spanned;
 
 use crate::consts::{constant, Constant};
 use crate::utils::paths;
-use crate::utils::{match_type, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty};
 
-/// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
-/// from other `Duration` methods.
-///
-/// **Why is this bad?** It's more concise to call `Duration::subsec_micros()` or
-/// `Duration::subsec_millis()` than to calculate them.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let dur = Duration::new(5, 0);
-/// let _micros = dur.subsec_nanos() / 1_000;
-/// let _millis = dur.subsec_nanos() / 1_000_000;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
+    /// from other `Duration` methods.
+    ///
+    /// **Why is this bad?** It's more concise to call `Duration::subsec_micros()` or
+    /// `Duration::subsec_millis()` than to calculate them.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let dur = Duration::new(5, 0);
+    /// let _micros = dur.subsec_nanos() / 1_000;
+    /// let _millis = dur.subsec_nanos() / 1_000_000;
+    /// ```
     pub DURATION_SUBSEC,
     complexity,
     "checks for calculation of subsecond microseconds or milliseconds"
 }
 
-#[derive(Copy, Clone)]
-pub struct DurationSubsec;
-
-impl LintPass for DurationSubsec {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DURATION_SUBSEC)
-    }
-}
+declare_lint_pass!(DurationSubsec => [DURATION_SUBSEC]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
             if let ExprKind::Binary(Spanned { node: BinOpKind::Div, .. }, ref left, ref right) = expr.node;
             if let ExprKind::MethodCall(ref method_path, _ , ref args) = left.node;
-            if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &paths::DURATION);
+            if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &*paths::DURATION);
             if let Some((Constant::Int(divisor), _)) = constant(cx, cx.tables, right);
             then {
                 let suggested_fn = match (method_path.ident.as_str().as_ref(), divisor) {
-                    ("subsec_micros", 1_000) => "subsec_millis",
+                    ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
                     ("subsec_nanos", 1_000) => "subsec_micros",
-                    ("subsec_nanos", 1_000_000) => "subsec_millis",
                     _ => return,
                 };
+                let mut applicability = Applicability::MachineApplicable;
                 span_lint_and_sugg(
                     cx,
                     DURATION_SUBSEC,
                     expr.span,
                     &format!("Calling `{}()` is more concise than this calculation", suggested_fn),
                     "try",
-                    format!("{}.{}()", snippet(cx, args[0].span, "_"), suggested_fn),
+                    format!(
+                        "{}.{}()",
+                        snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
+                        suggested_fn
+                    ),
+                    applicability,
                 );
             }
         }
index 39404bbafcca7cc53c608a6304da04ce3d70f8c1..25a1cde6e5ee74d80c599793fd4ba14e4be0280c 100644 (file)
@@ -1,52 +1,45 @@
-//! lint on if expressions with an else if, but without a final else branch
+//! Lint on if expressions with an else if, but without a final else branch.
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::*;
 
-use crate::utils::span_lint_and_sugg;
+use crate::utils::span_help_and_lint;
 
-/// **What it does:** Checks for usage of if expressions with an `else if` branch,
-/// but without a final `else` branch.
-///
-/// **Why is this bad?** Some coding guidelines require this (e.g. MISRA-C:2004 Rule 14.10).
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if x.is_positive() {
-///     a();
-/// } else if x.is_negative() {
-///     b();
-/// }
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// if x.is_positive() {
-///     a();
-/// } else if x.is_negative() {
-///     b();
-/// } else {
-///     // we don't care about zero
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of if expressions with an `else if` branch,
+    /// but without a final `else` branch.
+    ///
+    /// **Why is this bad?** Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if x.is_positive() {
+    ///     a();
+    /// } else if x.is_negative() {
+    ///     b();
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// if x.is_positive() {
+    ///     a();
+    /// } else if x.is_negative() {
+    ///     b();
+    /// } else {
+    ///     // We don't care about zero.
+    /// }
+    /// ```
     pub ELSE_IF_WITHOUT_ELSE,
     restriction,
     "if expression with an `else if`, but without a final `else` branch"
 }
 
-#[derive(Copy, Clone)]
-pub struct ElseIfWithoutElse;
-
-impl LintPass for ElseIfWithoutElse {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ELSE_IF_WITHOUT_ELSE)
-    }
-}
+declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
 
 impl EarlyLintPass for ElseIfWithoutElse {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
@@ -56,13 +49,12 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
 
         while let ExprKind::If(_, _, Some(ref els)) = item.node {
             if let ExprKind::If(_, _, None) = els.node {
-                span_lint_and_sugg(
+                span_help_and_lint(
                     cx,
                     ELSE_IF_WITHOUT_ELSE,
                     els.span,
                     "if expression with an `else if`, but without a final `else`",
                     "add an `else` block here",
-                    "".to_string()
                 );
             }
 
index f95ae32d5611d87dfc9b24f8b0fe08f9a2a7b771..e8d25384ee6a9e7c5233b61df0b1729dd0e9aa20 100644 (file)
@@ -1,47 +1,42 @@
 //! lint when there is an enum with no variants
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
 use crate::utils::span_lint_and_then;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for `enum`s with no variants.
-///
-/// **Why is this bad?** Enum's with no variants should be replaced with `!`,
-/// the uninhabited type,
-/// or a wrapper around it.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Test {}
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `enum`s with no variants.
+    ///
+    /// **Why is this bad?** Enum's with no variants should be replaced with `!`,
+    /// the uninhabited type,
+    /// or a wrapper around it.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Test {}
+    /// ```
     pub EMPTY_ENUM,
     pedantic,
     "enum with no variants"
 }
 
-#[derive(Copy, Clone)]
-pub struct EmptyEnum;
-
-impl LintPass for EmptyEnum {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(EMPTY_ENUM)
-    }
-}
+declare_lint_pass!(EmptyEnum => [EMPTY_ENUM]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item) {
-        let did = cx.tcx.hir.local_def_id(item.id);
+        let did = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
         if let ItemKind::Enum(..) = item.node {
             let ty = cx.tcx.type_of(did);
-            let adt = ty.ty_adt_def()
-                .expect("already checked whether this is an enum");
+            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
             if adt.variants.is_empty() {
                 span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| {
-                    db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it");
+                    db.span_help(
+                        item.span,
+                        "consider using the uninhabited type `!` or a wrapper around it",
+                    );
                 });
             }
         }
index 26ee6be5796ba1a4f3bc4916b414613c4faad732..66ae2966dfbb580bf9771a907cba49c5e01281e4 100644 (file)
@@ -1,59 +1,59 @@
-use rustc::hir::*;
-use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use syntax::codemap::Span;
+use crate::utils::sym;
 use crate::utils::SpanlessEq;
-use crate::utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty};
+use crate::utils::{get_item_name, higher, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty};
+use if_chain::if_chain;
+use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for uses of `contains_key` + `insert` on `HashMap`
-/// or `BTreeMap`.
-///
-/// **Why is this bad?** Using `entry` is more efficient.
-///
-/// **Known problems:** Some false negatives, eg.:
-/// ```rust
-/// let k = &key;
-/// if !m.contains_key(k) { m.insert(k.clone(), v); }
-/// ```
-///
-/// **Example:**
-/// ```rust
-/// if !m.contains_key(&k) { m.insert(k, v) }
-/// ```
-/// can be rewritten as:
-/// ```rust
-/// m.entry(k).or_insert(v);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for uses of `contains_key` + `insert` on `HashMap`
+    /// or `BTreeMap`.
+    ///
+    /// **Why is this bad?** Using `entry` is more efficient.
+    ///
+    /// **Known problems:** Some false negatives, eg.:
+    /// ```rust
+    /// let k = &key;
+    /// if !m.contains_key(k) {
+    ///     m.insert(k.clone(), v);
+    /// }
+    /// ```
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if !m.contains_key(&k) {
+    ///     m.insert(k, v)
+    /// }
+    /// ```
+    /// can be rewritten as:
+    /// ```rust
+    /// m.entry(k).or_insert(v);
+    /// ```
     pub MAP_ENTRY,
     perf,
     "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`"
 }
 
-#[derive(Copy, Clone)]
-pub struct HashMapLint;
-
-impl LintPass for HashMapLint {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MAP_ENTRY)
-    }
-}
+declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapPass {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if let ExprKind::If(ref check, ref then_block, ref else_block) = expr.node {
+        if let Some((ref check, ref then_block, ref else_block)) = higher::if_block(&expr) {
             if let ExprKind::Unary(UnOp::UnNot, ref check) = check.node {
                 if let Some((ty, map, key)) = check_cond(cx, check) {
                     // in case of `if !m.contains_key(&k) { m.insert(k, v); }`
                     // we can give a better error message
                     let sole_expr = {
-                        else_block.is_none() && if let ExprKind::Block(ref then_block, _) = then_block.node {
-                            (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1
-                        } else {
-                            true
-                        }
+                        else_block.is_none()
+                            && if let ExprKind::Block(ref then_block, _) = then_block.node {
+                                (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1
+                            } else {
+                                true
+                            }
                     };
 
                     let mut visitor = InsertVisitor {
@@ -92,16 +92,16 @@ fn check_cond<'a, 'tcx, 'b>(
     if_chain! {
         if let ExprKind::MethodCall(ref path, _, ref params) = check.node;
         if params.len() >= 2;
-        if path.ident.name == "contains_key";
+        if path.ident.name == *sym::contains_key;
         if let ExprKind::AddrOf(_, ref key) = params[1].node;
         then {
             let map = &params[0];
             let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(map));
 
-            return if match_type(cx, obj_ty, &paths::BTREEMAP) {
+            return if match_type(cx, obj_ty, &*paths::BTREEMAP) {
                 Some(("BTreeMap", map, key))
             }
-            else if match_type(cx, obj_ty, &paths::HASHMAP) {
+            else if match_type(cx, obj_ty, &*paths::HASHMAP) {
                 Some(("HashMap", map, key))
             }
             else {
@@ -127,7 +127,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         if_chain! {
             if let ExprKind::MethodCall(ref path, _, ref params) = expr.node;
             if params.len() == 3;
-            if path.ident.name == "insert";
+            if path.ident.name == *sym::insert;
             if get_item_name(self.cx, self.map) == get_item_name(self.cx, &params[0]);
             if SpanlessEq::new(self.cx).eq_expr(self.key, &params[1]);
             then {
@@ -139,14 +139,24 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                                            snippet(self.cx, params[1].span, ".."),
                                            snippet(self.cx, params[2].span, ".."));
 
-                        db.span_suggestion(self.span, "consider using", help);
+                        db.span_suggestion(
+                            self.span,
+                            "consider using",
+                            help,
+                            Applicability::MachineApplicable, // snippet
+                        );
                     }
                     else {
                         let help = format!("{}.entry({})",
                                            snippet(self.cx, self.map.span, "map"),
                                            snippet(self.cx, params[1].span, ".."));
 
-                        db.span_suggestion(self.span, "consider using", help);
+                        db.span_suggestion(
+                            self.span,
+                            "consider using",
+                            help,
+                            Applicability::MachineApplicable, // snippet
+                        );
                     }
                 });
             }
index 62cbead192907d9719f75defc0b99a07348adf1c..90cb78ae0366106623996cf6a994511d7c2a3098 100644 (file)
@@ -1,49 +1,43 @@
 //! lint on C-like enums that are `repr(isize/usize)` and have values that
 //! don't fit into an `i32`
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::consts::{miri_to_const, Constant};
+use crate::utils::span_lint;
 use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::mir::interpret::GlobalId;
 use rustc::ty;
-use rustc::ty::subst::Substs;
-use syntax::ast::{IntTy, UintTy};
-use crate::utils::span_lint;
-use crate::consts::{Constant, miri_to_const};
+use rustc::ty::subst::InternalSubsts;
 use rustc::ty::util::IntTypeExt;
-use rustc::mir::interpret::GlobalId;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::ast::{IntTy, UintTy};
 
-/// **What it does:** Checks for C-like enumerations that are
-/// `repr(isize/usize)` and have values that don't fit into an `i32`.
-///
-/// **Why is this bad?** This will truncate the variant value on 32 bit
-/// architectures, but works fine on 64 bit.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// #[repr(usize)]
-/// enum NonPortable {
-///     X = 0x1_0000_0000,
-///     Y = 0
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for C-like enumerations that are
+    /// `repr(isize/usize)` and have values that don't fit into an `i32`.
+    ///
+    /// **Why is this bad?** This will truncate the variant value on 32 bit
+    /// architectures, but works fine on 64 bit.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// #[repr(usize)]
+    /// enum NonPortable {
+    ///     X = 0x1_0000_0000,
+    ///     Y = 0,
+    /// }
+    /// ```
     pub ENUM_CLIKE_UNPORTABLE_VARIANT,
     correctness,
     "C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`"
 }
 
-pub struct UnportableVariant;
-
-impl LintPass for UnportableVariant {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT)
-    }
-}
+declare_lint_pass!(UnportableVariant => [ENUM_CLIKE_UNPORTABLE_VARIANT]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
-    #[allow(cast_possible_truncation, cast_sign_loss)]
+    #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss)]
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if cx.tcx.data_layout.pointer_size.bits() != 64 {
             return;
@@ -53,29 +47,29 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
                 let variant = &var.node;
                 if let Some(ref anon_const) = variant.disr_expr {
                     let param_env = ty::ParamEnv::empty();
-                    let did = cx.tcx.hir.body_owner_def_id(anon_const.body);
-                    let substs = Substs::identity_for_item(cx.tcx.global_tcx(), did);
-                    let instance = ty::Instance::new(did, substs);
-                    let cid = GlobalId {
+                    let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
+                    let substs = InternalSubsts::identity_for_item(cx.tcx.global_tcx(), def_id);
+                    let instance = ty::Instance::new(def_id, substs);
+                    let c_id = GlobalId {
                         instance,
-                        promoted: None
+                        promoted: None,
                     };
-                    let constant = cx.tcx.const_eval(param_env.and(cid)).ok();
-                    if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) {
-                        let mut ty = cx.tcx.type_of(did);
-                        if let ty::TyAdt(adt, _) = ty.sty {
+                    let constant = cx.tcx.const_eval(param_env.and(c_id)).ok();
+                    if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, &c)) {
+                        let mut ty = cx.tcx.type_of(def_id);
+                        if let ty::Adt(adt, _) = ty.sty {
                             if adt.is_enum() {
                                 ty = adt.repr.discr_type().to_ty(cx.tcx);
                             }
                         }
                         match ty.sty {
-                            ty::TyInt(IntTy::Isize) => {
+                            ty::Int(IntTy::Isize) => {
                                 let val = ((val as i128) << 64) >> 64;
                                 if val <= i128::from(i32::max_value()) && val >= i128::from(i32::min_value()) {
                                     continue;
                                 }
-                            }
-                            ty::TyUint(UintTy::Usize) if val > u128::from(u32::max_value()) => {},
+                            },
+                            ty::Uint(UintTy::Usize) if val > u128::from(u32::max_value()) => {},
                             _ => continue,
                         }
                         span_lint(
index 6f8afc710de66173be773dc2099cb2c4e7692403..d658e9baf5dbeb050e2a2582b950de46e44db1c0 100644 (file)
@@ -1,61 +1,50 @@
 //! lint on `use`ing all variants of an enum
 
+use crate::utils::span_lint;
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::*;
-use rustc::hir::def::Def;
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
-use syntax::ast::NodeId;
-use syntax::codemap::Span;
-use crate::utils::span_lint;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for `use Enum::*`.
-///
-/// **Why is this bad?** It is usually better style to use the prefixed name of
-/// an enumeration variant, rather than importing variants.
-///
-/// **Known problems:** Old-style enumerations that prefix the variants are
-/// still around.
-///
-/// **Example:**
-/// ```rust
-/// use std::cmp::Ordering::*;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `use Enum::*`.
+    ///
+    /// **Why is this bad?** It is usually better style to use the prefixed name of
+    /// an enumeration variant, rather than importing variants.
+    ///
+    /// **Known problems:** Old-style enumerations that prefix the variants are
+    /// still around.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::cmp::Ordering::*;
+    /// ```
     pub ENUM_GLOB_USE,
     pedantic,
     "use items that import all variants of an enum"
 }
 
-pub struct EnumGlobUse;
-
-impl LintPass for EnumGlobUse {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ENUM_GLOB_USE)
-    }
-}
+declare_lint_pass!(EnumGlobUse => [ENUM_GLOB_USE]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse {
-    fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: NodeId) {
+    fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: HirId) {
+        let map = cx.tcx.hir();
         // only check top level `use` statements
         for item in &m.item_ids {
-            self.lint_item(cx, cx.tcx.hir.expect_item(item.id));
+            self.lint_item(cx, map.expect_item(map.hir_to_node_id(item.id)));
         }
     }
 }
 
 impl EnumGlobUse {
-    fn lint_item(&self, cx: &LateContext<'_, '_>, item: &Item) {
+    fn lint_item(self, cx: &LateContext<'_, '_>, item: &Item) {
         if item.vis.node.is_pub() {
             return; // re-exports are fine
         }
         if let ItemKind::Use(ref path, UseKind::Glob) = item.node {
-            if let Def::Enum(_) = path.def {
-                span_lint(
-                    cx,
-                    ENUM_GLOB_USE,
-                    item.span,
-                    "don't use glob imports for enum variants",
-                );
+            if let Res::Def(DefKind::Enum, _) = path.res {
+                span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
             }
         }
     }
index 16c9212e5db86b344402feeb36a9d5abd831ce31..4479349aaf4a0530b474417b1ed40a119033b058 100644 (file)
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::ast::*;
-use syntax::codemap::Span;
-use syntax::symbol::LocalInternedString;
+use crate::utils::{camel_case, in_macro_or_desugar, is_present_in_source};
 use crate::utils::{span_help_and_lint, span_lint};
-use crate::utils::{camel_case_from, camel_case_until, in_macro};
+use rustc::lint::{EarlyContext, EarlyLintPass, Lint, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use syntax::ast::*;
+use syntax::source_map::Span;
+use syntax::symbol::{InternedString, LocalInternedString};
 
-/// **What it does:** Detects enumeration variants that are prefixed or suffixed
-/// by the same characters.
-///
-/// **Why is this bad?** Enumeration variant names should specify their variant,
-/// not repeat the enumeration name.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Cake {
-///     BlackForestCake,
-///     HummingbirdCake,
-///     BattenbergCake,
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects enumeration variants that are prefixed or suffixed
+    /// by the same characters.
+    ///
+    /// **Why is this bad?** Enumeration variant names should specify their variant,
+    /// not repeat the enumeration name.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Cake {
+    ///     BlackForestCake,
+    ///     HummingbirdCake,
+    ///     BattenbergCake,
+    /// }
+    /// ```
     pub ENUM_VARIANT_NAMES,
     style,
     "enums where all variants share a prefix/postfix"
 }
 
-/// **What it does:** Detects enumeration variants that are prefixed or suffixed
-/// by the same characters.
-///
-/// **Why is this bad?** Enumeration variant names should specify their variant,
-/// not repeat the enumeration name.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Cake {
-///     BlackForestCake,
-///     HummingbirdCake,
-///     BattenbergCake,
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects enumeration variants that are prefixed or suffixed
+    /// by the same characters.
+    ///
+    /// **Why is this bad?** Enumeration variant names should specify their variant,
+    /// not repeat the enumeration name.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Cake {
+    ///     BlackForestCake,
+    ///     HummingbirdCake,
+    ///     BattenbergCake,
+    /// }
+    /// ```
     pub PUB_ENUM_VARIANT_NAMES,
     pedantic,
     "enums where all variants share a prefix/postfix"
 }
 
-/// **What it does:** Detects type names that are prefixed or suffixed by the
-/// containing module's name.
-///
-/// **Why is this bad?** It requires the user to type the module name twice.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// mod cake {
-///     struct BlackForestCake;
-/// }
-/// ```
 declare_clippy_lint! {
-    pub STUTTER,
+    /// **What it does:** Detects type names that are prefixed or suffixed by the
+    /// containing module's name.
+    ///
+    /// **Why is this bad?** It requires the user to type the module name twice.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// mod cake {
+    ///     struct BlackForestCake;
+    /// }
+    /// ```
+    pub MODULE_NAME_REPETITIONS,
     pedantic,
     "type names prefixed/postfixed with their containing module's name"
 }
 
-/// **What it does:** Checks for modules that have the same name as their
-/// parent module
-///
-/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and
-/// again `mod foo { ..
-/// }` in `foo.rs`.
-/// The expectation is that items inside the inner `mod foo { .. }` are then
-/// available
-/// through `foo::x`, but they are only available through
-/// `foo::foo::x`.
-/// If this is done on purpose, it would be better to choose a more
-/// representative module name.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// // lib.rs
-/// mod foo;
-/// // foo.rs
-/// mod foo {
-///     ...
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for modules that have the same name as their
+    /// parent module
+    ///
+    /// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and
+    /// again `mod foo { ..
+    /// }` in `foo.rs`.
+    /// The expectation is that items inside the inner `mod foo { .. }` are then
+    /// available
+    /// through `foo::x`, but they are only available through
+    /// `foo::foo::x`.
+    /// If this is done on purpose, it would be better to choose a more
+    /// representative module name.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// // lib.rs
+    /// mod foo;
+    /// // foo.rs
+    /// mod foo {
+    ///     ...
+    /// }
+    /// ```
     pub MODULE_INCEPTION,
     style,
     "modules that have the same name as their parent module"
 }
 
 pub struct EnumVariantNames {
-    modules: Vec<(LocalInternedString, String)>,
+    modules: Vec<(InternedString, String)>,
     threshold: u64,
 }
 
@@ -115,11 +115,12 @@ pub fn new(threshold: u64) -> Self {
     }
 }
 
-impl LintPass for EnumVariantNames {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ENUM_VARIANT_NAMES, PUB_ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION)
-    }
-}
+impl_lint_pass!(EnumVariantNames => [
+    ENUM_VARIANT_NAMES,
+    PUB_ENUM_VARIANT_NAMES,
+    MODULE_NAME_REPETITIONS,
+    MODULE_INCEPTION
+]);
 
 fn var2str(var: &Variant) -> LocalInternedString {
     var.node.ident.as_str()
@@ -129,10 +130,7 @@ fn var2str(var: &Variant) -> LocalInternedString {
 fn partial_match(pre: &str, name: &str) -> usize {
     let mut name_iter = name.chars();
     let _ = name_iter.next_back(); // make sure the name is never fully matched
-    pre.chars()
-        .zip(name_iter)
-        .take_while(|&(l, r)| l == r)
-        .count()
+    pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
 }
 
 /// Returns the number of chars that match from the end
@@ -146,8 +144,6 @@ fn partial_rmatch(post: &str, name: &str) -> usize {
         .count()
 }
 
-// FIXME: #600
-#[allow(while_let_on_iterator)]
 fn check_variant(
     cx: &EarlyContext<'_>,
     threshold: u64,
@@ -163,9 +159,7 @@ fn check_variant(
     for var in &def.variants {
         let name = var2str(var);
         if partial_match(item_name, &name) == item_name_chars
-            && name.chars()
-                .nth(item_name_chars)
-                .map_or(false, |c| !c.is_lowercase())
+            && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
         {
             span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
         }
@@ -174,19 +168,19 @@ fn check_variant(
         }
     }
     let first = var2str(&def.variants[0]);
-    let mut pre = &first[..camel_case_until(&*first)];
-    let mut post = &first[camel_case_from(&*first)..];
+    let mut pre = &first[..camel_case::until(&*first)];
+    let mut post = &first[camel_case::from(&*first)..];
     for var in &def.variants {
         let name = var2str(var);
 
         let pre_match = partial_match(pre, &name);
         pre = &pre[..pre_match];
-        let pre_camel = camel_case_until(pre);
+        let pre_camel = camel_case::until(pre);
         pre = &pre[..pre_camel];
         while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
             if next.is_lowercase() {
                 let last = pre.len() - last.len_utf8();
-                let last_camel = camel_case_until(&pre[..last]);
+                let last_camel = camel_case::until(&pre[..last]);
                 pre = &pre[..last_camel];
             } else {
                 break;
@@ -196,7 +190,7 @@ fn check_variant(
         let post_match = partial_rmatch(post, &name);
         let post_end = post.len() - post_match;
         post = &post[post_end..];
-        let post_camel = camel_case_from(post);
+        let post_camel = camel_case::from(post);
         post = &post[post_camel..];
     }
     let (what, value) = match (pre.is_empty(), post.is_empty()) {
@@ -245,11 +239,12 @@ fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
         assert!(last.is_some());
     }
 
+    #[allow(clippy::similar_names)]
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         let item_name = item.ident.as_str();
         let item_name_chars = item_name.chars().count();
         let item_camel = to_camel_case(&item_name);
-        if !in_macro(item.span) {
+        if !in_macro_or_desugar(item.span) && 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() {
@@ -268,19 +263,26 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
                         let rmatching = partial_rmatch(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
 
-                        let is_word_beginning = |c: char| {
-                            c == '_' || c.is_uppercase() || c.is_numeric()
-                        };
+                        let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
 
                         if matching == nchars {
                             match item_camel.chars().nth(nchars) {
-                                Some(c) if is_word_beginning(c) =>
-                                    span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"),
-                                _ => ()
+                                Some(c) if is_word_beginning(c) => span_lint(
+                                    cx,
+                                    MODULE_NAME_REPETITIONS,
+                                    item.span,
+                                    "item name starts with its containing module's name",
+                                ),
+                                _ => (),
                             }
                         }
                         if rmatching == nchars {
-                            span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name");
+                            span_lint(
+                                cx,
+                                MODULE_NAME_REPETITIONS,
+                                item.span,
+                                "item name ends with its containing module's name",
+                            );
                         }
                     }
                 }
@@ -293,6 +295,6 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
             };
             check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
         }
-        self.modules.push((item_name, item_camel));
+        self.modules.push((item_name.as_interned_str(), item_camel));
     }
 }
index dfbc3b126336eb136ed8f867bd4b2758921dad29..08c0b36855e2200e8ed1f1c72210dda8c3c9047f 100644 (file)
@@ -1,60 +1,58 @@
+use crate::utils::{
+    implements_trait, in_macro_or_desugar, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq,
+};
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use crate::utils::{in_macro, implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for equal operands to comparison, logical and
-/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
-/// `||`, `&`, `|`, `^`, `-` and `/`).
-///
-/// **Why is this bad?** This is usually just a typo or a copy and paste error.
-///
-/// **Known problems:** False negatives: We had some false positives regarding
-/// calls (notably [racer](https://github.com/phildawes/racer) had one instance
-/// of `x.pop() && x.pop()`), so we removed matching any function or method
-/// calls. We may introduce a whitelist of known pure functions in the future.
-///
-/// **Example:**
-/// ```rust
-/// x + 1 == x + 1
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for equal operands to comparison, logical and
+    /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
+    /// `||`, `&`, `|`, `^`, `-` and `/`).
+    ///
+    /// **Why is this bad?** This is usually just a typo or a copy and paste error.
+    ///
+    /// **Known problems:** False negatives: We had some false positives regarding
+    /// calls (notably [racer](https://github.com/phildawes/racer) had one instance
+    /// of `x.pop() && x.pop()`), so we removed matching any function or method
+    /// calls. We may introduce a whitelist of known pure functions in the future.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let x = 1;
+    /// if x + 1 == x + 1 {}
+    /// ```
     pub EQ_OP,
     correctness,
-    "equal operands on both sides of a comparison or bitwise combination (e.g. `x == x`)"
+    "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)"
 }
 
-/// **What it does:** Checks for arguments to `==` which have their address
-/// taken to satisfy a bound
-/// and suggests to dereference the other argument instead
-///
-/// **Why is this bad?** It is more idiomatic to dereference the other argument.
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// &x == y
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for arguments to `==` which have their address
+    /// taken to satisfy a bound
+    /// and suggests to dereference the other argument instead
+    ///
+    /// **Why is this bad?** It is more idiomatic to dereference the other argument.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// &x == y
+    /// ```
     pub OP_REF,
     style,
     "taking a reference to satisfy the type constraints on `==`"
 }
 
-#[derive(Copy, Clone)]
-pub struct EqOp;
-
-impl LintPass for EqOp {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(EQ_OP, OP_REF)
-    }
-}
+declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
 
 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(e.span) {
+            if in_macro_or_desugar(e.span) {
                 return;
             }
             if is_valid_operator(op) && SpanlessEq::new(cx).ignore_fn().eq_expr(left, right) {
@@ -80,10 +78,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                 BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false),
                 BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false),
                 BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true),
-                BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => (cx.tcx.lang_items().ord_trait(), true),
+                BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => {
+                    (cx.tcx.lang_items().ord_trait(), true)
+                },
             };
             if let Some(trait_id) = trait_id {
-                #[allow(match_same_arms)]
+                #[allow(clippy::match_same_arms)]
                 match (&left.node, &right.node) {
                     // do not suggest to dereference literals
                     (&ExprKind::Lit(..), _) | (_, &ExprKind::Lit(..)) => {},
@@ -110,12 +110,23 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                     );
                                 },
                             )
-                        } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()]) {
+                        } else if lcpy
+                            && !rcpy
+                            && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
+                        {
                             span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
                                 let lsnip = snippet(cx, l.span, "...").to_string();
-                                db.span_suggestion(left.span, "use the left value directly", lsnip);
+                                db.span_suggestion(
+                                    left.span,
+                                    "use the left value directly",
+                                    lsnip,
+                                    Applicability::MachineApplicable, // snippet
+                                );
                             })
-                        } else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()]) {
+                        } else if !lcpy
+                            && rcpy
+                            && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
+                        {
                             span_lint_and_then(
                                 cx,
                                 OP_REF,
@@ -123,7 +134,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                 "needlessly taken reference of right operand",
                                 |db| {
                                     let rsnip = snippet(cx, r.span, "...").to_string();
-                                    db.span_suggestion(right.span, "use the right value directly", rsnip);
+                                    db.span_suggestion(
+                                        right.span,
+                                        "use the right value directly",
+                                        rsnip,
+                                        Applicability::MachineApplicable, // snippet
+                                    );
                                 },
                             )
                         }
@@ -132,10 +148,17 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                     (&ExprKind::AddrOf(_, ref l), _) => {
                         let lty = cx.tables.expr_ty(l);
                         let lcpy = is_copy(cx, lty);
-                        if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()]) {
+                        if (requires_ref || lcpy)
+                            && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
+                        {
                             span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
                                 let lsnip = snippet(cx, l.span, "...").to_string();
-                                db.span_suggestion(left.span, "use the left value directly", lsnip);
+                                db.span_suggestion(
+                                    left.span,
+                                    "use the left value directly",
+                                    lsnip,
+                                    Applicability::MachineApplicable, // snippet
+                                );
                             })
                         }
                     },
@@ -143,10 +166,17 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                     (_, &ExprKind::AddrOf(_, ref r)) => {
                         let rty = cx.tables.expr_ty(r);
                         let rcpy = is_copy(cx, rty);
-                        if (requires_ref || rcpy) && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()]) {
+                        if (requires_ref || rcpy)
+                            && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
+                        {
                             span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| {
                                 let rsnip = snippet(cx, r.span, "...").to_string();
-                                db.span_suggestion(right.span, "use the right value directly", rsnip);
+                                db.span_suggestion(
+                                    right.span,
+                                    "use the right value directly",
+                                    rsnip,
+                                    Applicability::MachineApplicable, // snippet
+                                );
                             })
                         }
                     },
@@ -157,10 +187,21 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
     }
 }
 
-
 fn is_valid_operator(op: BinOp) -> bool {
     match op.node {
-        BinOpKind::Sub | BinOpKind::Div | BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge | BinOpKind::Ne | BinOpKind::And | BinOpKind::Or | BinOpKind::BitXor | BinOpKind::BitAnd | BinOpKind::BitOr => true,
+        BinOpKind::Sub
+        | BinOpKind::Div
+        | BinOpKind::Eq
+        | BinOpKind::Lt
+        | BinOpKind::Le
+        | BinOpKind::Gt
+        | BinOpKind::Ge
+        | BinOpKind::Ne
+        | BinOpKind::And
+        | BinOpKind::Or
+        | BinOpKind::BitXor
+        | BinOpKind::BitAnd
+        | BinOpKind::BitOr => true,
         _ => false,
     }
 }
index 4960a48b3c880c804e0f6a46dda160abebdf849b..3ac2f90ce01b4cd77f06bbffa95a35525c769d68 100644 (file)
@@ -1,40 +1,37 @@
-use crate::consts::{constant_simple, Constant};
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::codemap::Span;
-use crate::utils::{in_macro, span_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+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};
 
-/// **What it does:** Checks for erasing operations, e.g. `x * 0`.
-///
-/// **Why is this bad?** The whole expression can be replaced by zero.
-/// This is most likely not the intended outcome and should probably be
-/// corrected
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// 0 / x; 0 * x; x & 0
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for erasing operations, e.g., `x * 0`.
+    ///
+    /// **Why is this bad?** The whole expression can be replaced by zero.
+    /// This is most likely not the intended outcome and should probably be
+    /// corrected
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = 1;
+    /// 0 / x;
+    /// 0 * x;
+    /// x & 0;
+    /// ```
     pub ERASING_OP,
     correctness,
-    "using erasing operations, e.g. `x * 0` or `y & 0`"
+    "using erasing operations, e.g., `x * 0` or `y & 0`"
 }
 
-#[derive(Copy, Clone)]
-pub struct ErasingOp;
-
-impl LintPass for ErasingOp {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ERASING_OP)
-    }
-}
+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(e.span) {
+        if in_macro_or_desugar(e.span) {
             return;
         }
         if let ExprKind::Binary(ref cmp, ref left, ref right) = e.node {
index ebbc2c34811b51e34c68697174733f7556da5c0b..8870b3f3b0ce28e96c86eac8bfdd94611c8b7b42 100644 (file)
@@ -1,39 +1,39 @@
-use rustc::hir::*;
 use rustc::hir::intravisit as visit;
-use rustc::hir::map::Node::{NodeExpr, NodeStmt};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::middle::expr_use_visitor::*;
 use rustc::middle::mem_categorization::{cmt_, Categorization};
-use rustc::ty::{self, Ty};
 use rustc::ty::layout::LayoutOf;
-use rustc::util::nodemap::NodeSet;
-use syntax::ast::NodeId;
-use syntax::codemap::Span;
+use rustc::ty::{self, Ty};
+use rustc::util::nodemap::HirIdSet;
+use rustc::{declare_tool_lint, impl_lint_pass};
+use syntax::source_map::Span;
+
 use crate::utils::span_lint;
 
-pub struct Pass {
+#[derive(Copy, Clone)]
+pub struct BoxedLocal {
     pub too_large_for_stack: u64,
 }
 
-/// **What it does:** Checks for usage of `Box<T>` where an unboxed `T` would
-/// work fine.
-///
-/// **Why is this bad?** This is an unnecessary allocation, and bad for
-/// performance. It is only necessary to allocate if you wish to move the box
-/// into something.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn main() {
-///     let x = Box::new(1);
-///     foo(*x);
-///     println!("{}", *x);
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `Box<T>` where an unboxed `T` would
+    /// work fine.
+    ///
+    /// **Why is this bad?** This is an unnecessary allocation, and bad for
+    /// performance. It is only necessary to allocate if you wish to move the box
+    /// into something.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn main() {
+    ///     let x = Box::new(1);
+    ///     foo(*x);
+    ///     println!("{}", *x);
+    /// }
+    /// ```
     pub BOXED_LOCAL,
     perf,
     "using `Box<T>` where unnecessary"
@@ -45,17 +45,13 @@ fn is_non_trait_box(ty: Ty<'_>) -> bool {
 
 struct EscapeDelegate<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    set: NodeSet,
+    set: HirIdSet,
     too_large_for_stack: u64,
 }
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BOXED_LOCAL)
-    }
-}
+impl_lint_pass!(BoxedLocal => [BOXED_LOCAL]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -63,15 +59,25 @@ fn check_fn(
         _: &'tcx FnDecl,
         body: &'tcx Body,
         _: Span,
-        node_id: NodeId,
+        hir_id: HirId,
     ) {
-        let fn_def_id = cx.tcx.hir.local_def_id(node_id);
+        // If the method is an impl for a trait, don't warn.
+        let parent_id = cx.tcx.hir().get_parent_item(hir_id);
+        let parent_node = cx.tcx.hir().find_by_hir_id(parent_id);
+
+        if let Some(Node::Item(item)) = parent_node {
+            if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node {
+                return;
+            }
+        }
+
         let mut v = EscapeDelegate {
             cx,
-            set: NodeSet(),
+            set: HirIdSet::default(),
             too_large_for_stack: self.too_large_for_stack,
         };
 
+        let fn_def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id);
         let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
         ExprUseVisitor::new(&mut v, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).consume_body(body);
 
@@ -79,7 +85,7 @@ fn check_fn(
             span_lint(
                 cx,
                 BOXED_LOCAL,
-                cx.tcx.hir.span(node),
+                cx.tcx.hir().span_by_hir_id(node),
                 "local variable doesn't need to be boxed here",
             );
         }
@@ -87,9 +93,9 @@ fn check_fn(
 }
 
 impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
-    fn consume(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
+    fn consume(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
         if let Categorization::Local(lid) = cmt.cat {
-            if let Move(DirectRefMove) = mode {
+            if let Move(DirectRefMove) | Move(CaptureMove) = mode {
                 // moved out or in. clearly can't be localized
                 self.set.remove(&lid);
             }
@@ -97,32 +103,29 @@ fn consume(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, mode: ConsumeMode) {
     }
     fn matched_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: MatchMode) {}
     fn consume_pat(&mut self, consume_pat: &Pat, cmt: &cmt_<'tcx>, _: ConsumeMode) {
-        let map = &self.cx.tcx.hir;
-        if map.is_argument(consume_pat.id) {
+        let map = &self.cx.tcx.hir();
+        if map.is_argument(map.hir_to_node_id(consume_pat.hir_id)) {
             // Skip closure arguments
-            if let Some(NodeExpr(..)) = map.find(map.get_parent_node(consume_pat.id)) {
+            if let Some(Node::Expr(..)) = map.find_by_hir_id(map.get_parent_node_by_hir_id(consume_pat.hir_id)) {
                 return;
             }
             if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
-                self.set.insert(consume_pat.id);
+                self.set.insert(consume_pat.hir_id);
             }
             return;
         }
         if let Categorization::Rvalue(..) = cmt.cat {
-            let id = map.hir_to_node_id(cmt.hir_id);
-            if let Some(NodeStmt(st)) = map.find(map.get_parent_node(id)) {
-                if let StmtKind::Decl(ref decl, _) = st.node {
-                    if let DeclKind::Local(ref loc) = decl.node {
-                        if let Some(ref ex) = loc.init {
-                            if let ExprKind::Box(..) = ex.node {
-                                if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
-                                    // let x = box (...)
-                                    self.set.insert(consume_pat.id);
-                                }
-                                // TODO Box::new
-                                // TODO vec![]
-                                // TODO "foo".to_owned() and friends
+            if let Some(Node::Stmt(st)) = map.find_by_hir_id(map.get_parent_node_by_hir_id(cmt.hir_id)) {
+                if let StmtKind::Local(ref loc) = st.node {
+                    if let Some(ref ex) = loc.init {
+                        if let ExprKind::Box(..) = ex.node {
+                            if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) {
+                                // let x = box (...)
+                                self.set.insert(consume_pat.hir_id);
                             }
+                            // TODO Box::new
+                            // TODO vec![]
+                            // TODO "foo".to_owned() and friends
                         }
                     }
                 }
@@ -132,40 +135,47 @@ fn consume_pat(&mut self, consume_pat: &Pat, cmt: &cmt_<'tcx>, _: ConsumeMode) {
             if self.set.contains(&lid) {
                 // let y = x where x is known
                 // remove x, insert y
-                self.set.insert(consume_pat.id);
+                self.set.insert(consume_pat.hir_id);
                 self.set.remove(&lid);
             }
         }
     }
-    fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, loan_cause: LoanCause) {
+    fn borrow(
+        &mut self,
+        _: HirId,
+        _: Span,
+        cmt: &cmt_<'tcx>,
+        _: ty::Region<'_>,
+        _: ty::BorrowKind,
+        loan_cause: LoanCause,
+    ) {
         if let Categorization::Local(lid) = cmt.cat {
             match loan_cause {
-                // x.foo()
-                // Used without autodereffing (i.e. x.clone())
+                // `x.foo()`
+                // Used without autoderef-ing (i.e., `x.clone()`).
                 LoanCause::AutoRef |
 
-                // &x
-                // foo(&x) where no extra autoreffing is happening
+                // `&x`
+                // `foo(&x)` where no extra autoref-ing is happening.
                 LoanCause::AddrOf |
 
-                // `match x` can move
+                // `match x` can move.
                 LoanCause::MatchDiscriminant => {
                     self.set.remove(&lid);
                 }
 
-                // do nothing for matches, etc. These can't escape
+                // Do nothing for matches, etc. These can't escape.
                 _ => {}
             }
         }
     }
-    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
-    fn mutate(&mut self, _: NodeId, _: Span, _: &cmt_<'tcx>, _: MutateMode) {}
+    fn decl_without_init(&mut self, _: HirId, _: Span) {}
+    fn mutate(&mut self, _: HirId, _: Span, _: &cmt_<'tcx>, _: MutateMode) {}
 }
 
 impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
     fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
-        // Large types need to be boxed to avoid stack
-        // overflows.
+        // Large types need to be boxed to avoid stack overflows.
         if ty.is_box() {
             self.cx.layout_of(ty.boxed_ty()).ok().map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
         } else {
index 0e9532276f3b6417b74779bd07a0aea05b677d4c..4a93101d7cb9fad7a73e8168494d0e0cb844606b 100644 (file)
@@ -1,49 +1,73 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::ty;
+use if_chain::if_chain;
+use matches::matches;
 use rustc::hir::*;
-use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then};
-
-#[allow(missing_copy_implementations)]
-pub struct EtaPass;
-
-
-/// **What it does:** Checks for closures which just call another function where
-/// the function can be called directly. `unsafe` functions or calls where types
-/// get adjusted are ignored.
-///
-/// **Why is this bad?** Needlessly creating a closure adds code for no benefit
-/// and gives the optimizer more work.
-///
-/// **Known problems:** If creating the closure inside the closure has a side-
-/// effect then moving the closure creation out will change when that side-
-/// effect runs.
-/// See https://github.com/rust-lang-nursery/rust-clippy/issues/1439 for more
-/// details.
-///
-/// **Example:**
-/// ```rust
-/// xs.map(|x| foo(x))
-/// ```
-/// where `foo(_)` is a plain function that takes the exact argument type of
-/// `x`.
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+
+use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then, type_is_unsafe_function};
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for closures which just call another function where
+    /// the function can be called directly. `unsafe` functions or calls where types
+    /// get adjusted are ignored.
+    ///
+    /// **Why is this bad?** Needlessly creating a closure adds code for no benefit
+    /// and gives the optimizer more work.
+    ///
+    /// **Known problems:** If creating the closure inside the closure has a side-
+    /// effect then moving the closure creation out will change when that side-
+    /// effect runs.
+    /// See rust-lang/rust-clippy#1439 for more details.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// xs.map(|x| foo(x))
+    /// ```
+    /// where `foo(_)` is a plain function that takes the exact argument type of
+    /// `x`.
     pub REDUNDANT_CLOSURE,
     style,
-    "redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)"
+    "redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
 }
 
-impl LintPass for EtaPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(REDUNDANT_CLOSURE)
-    }
+declare_clippy_lint! {
+    /// **What it does:** Checks for closures which only invoke a method on the closure
+    /// argument and can be replaced by referencing the method directly.
+    ///
+    /// **Why is this bad?** It's unnecessary to create the closure.
+    ///
+    /// **Known problems:** rust-lang/rust-clippy#3071, rust-lang/rust-clippy#4002,
+    /// rust-lang/rust-clippy#3942
+    ///
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// Some('a').map(|s| s.to_uppercase());
+    /// ```
+    /// may be rewritten as
+    /// ```rust,ignore
+    /// Some('a').map(char::to_uppercase);
+    /// ```
+    pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+    pedantic,
+    "redundant closures for method calls"
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
+declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaReduction {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if in_external_macro(cx.sess(), expr.span) {
+            return;
+        }
+
         match expr.node {
-            ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => for arg in args {
-                check_closure(cx, arg)
+            ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
+                for arg in args {
+                    check_closure(cx, arg)
+                }
             },
             _ => (),
         }
@@ -52,53 +76,146 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
 
 fn check_closure(cx: &LateContext<'_, '_>, expr: &Expr) {
     if let ExprKind::Closure(_, ref decl, eid, _, _) = expr.node {
-        let body = cx.tcx.hir.body(eid);
+        let body = cx.tcx.hir().body(eid);
         let ex = &body.value;
-        if let ExprKind::Call(ref caller, ref args) = ex.node {
-            if args.len() != decl.inputs.len() {
-                // Not the same number of arguments, there
-                // is no way the closure is the same as the function
-                return;
-            }
-            if is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)) {
-                // Are the expression or the arguments type-adjusted? Then we need the closure
-                return;
-            }
+
+        if_chain!(
+            if let ExprKind::Call(ref caller, ref args) = ex.node;
+
+            // Not the same number of arguments, there is no way the closure is the same as the function return;
+            if args.len() == decl.inputs.len();
+
+            // Are the expression or the arguments type-adjusted? Then we need the closure
+            if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));
+
             let fn_ty = cx.tables.expr_ty(caller);
-            match fn_ty.sty {
-                // Is it an unsafe function? They don't implement the closure traits
-                ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-                    let sig = fn_ty.fn_sig(cx.tcx);
-                    if sig.skip_binder().unsafety == Unsafety::Unsafe || sig.skip_binder().output().sty == ty::TyNever {
-                        return;
+
+            if matches!(fn_ty.sty, ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
+
+            if !type_is_unsafe_function(cx, fn_ty);
+
+            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());
+
+            then {
+                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
+                    if let Some(snippet) = snippet_opt(cx, caller.span) {
+                        db.span_suggestion(
+                            expr.span,
+                            "remove closure as shown",
+                            snippet,
+                            Applicability::MachineApplicable,
+                        );
                     }
-                },
-                _ => (),
+                });
             }
-            for (a1, a2) in iter_input_pats(decl, body).zip(args) {
-                if let PatKind::Binding(_, _, ident, _) = a1.pat.node {
-                    // XXXManishearth Should I be checking the binding mode here?
-                    if let ExprKind::Path(QPath::Resolved(None, ref p)) = a2.node {
-                        if p.segments.len() != 1 {
-                            // If it's a proper path, it can't be a local variable
-                            return;
-                        }
-                        if p.segments[0].ident.name != ident.name {
-                            // The two idents should be the same
-                            return;
-                        }
-                    } else {
-                        return;
-                    }
-                } else {
-                    return;
-                }
+        );
+
+        if_chain!(
+            if let ExprKind::MethodCall(ref path, _, ref args) = ex.node;
+
+            // Not the same number of arguments, there is no way the closure is the same as the function return;
+            if args.len() == decl.inputs.len();
+
+            // Are the expression or the arguments type-adjusted? Then we need the closure
+            if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));
+
+            let method_def_id = cx.tables.type_dependent_def_id(ex.hir_id).unwrap();
+            if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));
+
+            if compare_inputs(&mut iter_input_pats(decl, body), &mut args.into_iter());
+
+            if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);
+
+            then {
+                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure found", |db| {
+                    db.span_suggestion(
+                        expr.span,
+                        "remove closure as shown",
+                        format!("{}::{}", name, path.ident.name),
+                        Applicability::MachineApplicable,
+                    );
+                });
             }
-            span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure found", |db| {
-                if let Some(snippet) = snippet_opt(cx, caller.span) {
-                    db.span_suggestion(expr.span, "remove closure as shown", snippet);
+        );
+    }
+}
+
+/// Tries to determine the type for universal function call to be used instead of the closure
+fn get_ufcs_type_name(
+    cx: &LateContext<'_, '_>,
+    method_def_id: def_id::DefId,
+    self_arg: &Expr,
+) -> std::option::Option<String> {
+    let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
+    let actual_type_of_self = &cx.tables.node_type(self_arg.hir_id);
+
+    if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
+        if match_borrow_depth(expected_type_of_self, &actual_type_of_self) {
+            return Some(cx.tcx.def_path_str(trait_id));
+        }
+    }
+
+    cx.tcx.impl_of_method(method_def_id).and_then(|_| {
+        //a type may implicitly implement other type's methods (e.g. Deref)
+        if match_types(expected_type_of_self, &actual_type_of_self) {
+            return Some(get_type_name(cx, &actual_type_of_self));
+        }
+        None
+    })
+}
+
+fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
+    match (&lhs.sty, &rhs.sty) {
+        (ty::Ref(_, t1, _), ty::Ref(_, t2, _)) => match_borrow_depth(&t1, &t2),
+        (l, r) => match (l, r) {
+            (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _)) => false,
+            (_, _) => true,
+        },
+    }
+}
+
+fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
+    match (&lhs.sty, &rhs.sty) {
+        (ty::Bool, ty::Bool)
+        | (ty::Char, ty::Char)
+        | (ty::Int(_), ty::Int(_))
+        | (ty::Uint(_), ty::Uint(_))
+        | (ty::Str, ty::Str) => true,
+        (ty::Ref(_, t1, _), ty::Ref(_, t2, _))
+        | (ty::Array(t1, _), ty::Array(t2, _))
+        | (ty::Slice(t1), ty::Slice(t2)) => match_types(t1, t2),
+        (ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
+        (_, _) => false,
+    }
+}
+
+fn get_type_name(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> String {
+    match ty.sty {
+        ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
+        ty::Ref(_, r, _) => get_type_name(cx, &r),
+        _ => ty.to_string(),
+    }
+}
+
+fn compare_inputs(closure_inputs: &mut dyn Iterator<Item = &Arg>, call_args: &mut dyn Iterator<Item = &Expr>) -> bool {
+    for (closure_input, function_arg) in closure_inputs.zip(call_args) {
+        if let PatKind::Binding(_, _, ident, _) = closure_input.pat.node {
+            // XXXManishearth Should I be checking the binding mode here?
+            if let ExprKind::Path(QPath::Resolved(None, ref p)) = function_arg.node {
+                if p.segments.len() != 1 {
+                    // If it's a proper path, it can't be a local variable
+                    return false;
+                }
+                if p.segments[0].ident.name != ident.name {
+                    // The two idents should be the same
+                    return false;
                 }
-            });
+            } else {
+                return false;
+            }
+        } else {
+            return false;
         }
     }
+    true
 }
index 7ccf8c31569d864c3edfc3a1123a7ef1e917cab6..dc98158c50991dc2a45297fe1fd578a3028e3b99 100644 (file)
@@ -1,80 +1,77 @@
+use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
+use if_chain::if_chain;
 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use syntax::ast;
-use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for a read and a write to the same variable where
-/// whether the read occurs before or after the write depends on the evaluation
-/// order of sub-expressions.
-///
-/// **Why is this bad?** It is often confusing to read. In addition, the
-/// sub-expression evaluation order for Rust is not well documented.
-///
-/// **Known problems:** Code which intentionally depends on the evaluation
-/// order, or which is correct for any evaluation order.
-///
-/// **Example:**
-/// ```rust
-/// let mut x = 0;
-/// let a = {x = 1; 1} + x;
-/// // Unclear whether a is 1 or 2.
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for a read and a write to the same variable where
+    /// whether the read occurs before or after the write depends on the evaluation
+    /// order of sub-expressions.
+    ///
+    /// **Why is this bad?** It is often confusing to read. In addition, the
+    /// sub-expression evaluation order for Rust is not well documented.
+    ///
+    /// **Known problems:** Code which intentionally depends on the evaluation
+    /// order, or which is correct for any evaluation order.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut x = 0;
+    /// let a = {
+    ///     x = 1;
+    ///     1
+    /// } + x;
+    /// // Unclear whether a is 1 or 2.
+    /// ```
     pub EVAL_ORDER_DEPENDENCE,
     complexity,
     "whether a variable read occurs before a write depends on sub-expression evaluation order"
 }
 
-/// **What it does:** Checks for diverging calls that are not match arms or
-/// statements.
-///
-/// **Why is this bad?** It is often confusing to read. In addition, the
-/// sub-expression evaluation order for Rust is not well documented.
-///
-/// **Known problems:** Someone might want to use `some_bool || panic!()` as a
-/// shorthand.
-///
-/// **Example:**
-/// ```rust
-/// let a = b() || panic!() || c();
-/// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
-/// let x = (a, b, c, panic!());
-/// // can simply be replaced by `panic!()`
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for diverging calls that are not match arms or
+    /// statements.
+    ///
+    /// **Why is this bad?** It is often confusing to read. In addition, the
+    /// sub-expression evaluation order for Rust is not well documented.
+    ///
+    /// **Known problems:** Someone might want to use `some_bool || panic!()` as a
+    /// shorthand.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let a = b() || panic!() || c();
+    /// // `c()` is dead, `panic!()` is only called if `b()` returns `false`
+    /// let x = (a, b, c, panic!());
+    /// // can simply be replaced by `panic!()`
+    /// ```
     pub DIVERGING_SUB_EXPRESSION,
     complexity,
     "whether an expression contains a diverging sub expression"
 }
 
-#[derive(Copy, Clone)]
-pub struct EvalOrderDependence;
-
-impl LintPass for EvalOrderDependence {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION)
-    }
-}
+declare_lint_pass!(EvalOrderDependence => [EVAL_ORDER_DEPENDENCE, DIVERGING_SUB_EXPRESSION]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         // Find a write to a local variable.
         match expr.node {
-            ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => if let ExprKind::Path(ref qpath) = lhs.node {
-                if let QPath::Resolved(_, ref path) = *qpath {
-                    if path.segments.len() == 1 {
-                        if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
-                            let mut visitor = ReadVisitor {
-                                cx,
-                                var,
-                                write_expr: expr,
-                                last_expr: expr,
-                            };
-                            check_for_unsequenced_reads(&mut visitor);
+            ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => {
+                if let ExprKind::Path(ref qpath) = lhs.node {
+                    if let QPath::Resolved(_, ref path) = *qpath {
+                        if path.segments.len() == 1 {
+                            if let def::Res::Local(var) = cx.tables.qpath_res(qpath, lhs.hir_id) {
+                                let mut visitor = ReadVisitor {
+                                    cx,
+                                    var,
+                                    write_expr: expr,
+                                    last_expr: expr,
+                                };
+                                check_for_unsequenced_reads(&mut visitor);
+                            }
                         }
                     }
                 }
@@ -84,15 +81,13 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
         match stmt.node {
-            StmtKind::Expr(ref e, _) | StmtKind::Semi(ref e, _) => DivergenceVisitor { cx }.maybe_walk_expr(e),
-            StmtKind::Decl(ref d, _) => if let DeclKind::Local(ref local) = d.node {
-                if let Local {
-                    init: Some(ref e), ..
-                } = **local
-                {
+            StmtKind::Local(ref local) => {
+                if let Local { init: Some(ref e), .. } = **local {
                     DivergenceVisitor { cx }.visit_expr(e);
                 }
             },
+            StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => DivergenceVisitor { cx }.maybe_walk_expr(e),
+            StmtKind::Item(..) => {},
         }
     }
 }
@@ -109,7 +104,9 @@ fn maybe_walk_expr(&mut self, e: &'tcx Expr) {
                 self.visit_expr(e);
                 for arm in arms {
                     if let Some(ref guard) = arm.guard {
-                        self.visit_expr(guard);
+                        match guard {
+                            Guard::If(if_expr) => self.visit_expr(if_expr),
+                        }
                     }
                     // make sure top level arm expressions aren't linted
                     self.maybe_walk_expr(&*arm.body);
@@ -130,9 +127,9 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
             ExprKind::Call(ref func, _) => {
                 let typ = self.cx.tables.expr_ty(func);
                 match typ.sty {
-                    ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+                    ty::FnDef(..) | ty::FnPtr(_) => {
                         let sig = typ.fn_sig(self.cx.tcx);
-                        if let ty::TyNever = self.cx.tcx.erase_late_bound_regions(&sig).output().sty {
+                        if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().sty {
                             self.report_diverging_sub_expr(e);
                         }
                     },
@@ -167,31 +164,31 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 /// This means reads for which there is a common ancestor between the read and
 /// the write such that
 ///
-/// * evaluating the ancestor necessarily evaluates both the read and the write
-///   (for example, `&x` and `|| x = 1` don't necessarily evaluate `x`), and
+/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
+///   and `|| x = 1` don't necessarily evaluate `x`), and
 ///
-/// * which one is evaluated first depends on the order of sub-expression
-///   evaluation. Blocks, `if`s, loops, `match`es, and the short-circuiting
-///   logical operators are considered to have a defined evaluation order.
+/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
+///   loops, `match`es, and the short-circuiting logical operators are considered to have a defined
+///   evaluation order.
 ///
 /// When such a read is found, the lint is triggered.
 fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
-    let map = &vis.cx.tcx.hir;
-    let mut cur_id = vis.write_expr.id;
+    let map = &vis.cx.tcx.hir();
+    let mut cur_id = vis.write_expr.hir_id;
     loop {
-        let parent_id = map.get_parent_node(cur_id);
+        let parent_id = map.get_parent_node_by_hir_id(cur_id);
         if parent_id == cur_id {
             break;
         }
-        let parent_node = match map.find(parent_id) {
+        let parent_node = match map.find_by_hir_id(parent_id) {
             Some(parent) => parent,
             None => break,
         };
 
         let stop_early = match parent_node {
-            map::Node::NodeExpr(expr) => check_expr(vis, expr),
-            map::Node::NodeStmt(stmt) => check_stmt(vis, stmt),
-            map::Node::NodeItem(_) => {
+            Node::Expr(expr) => check_expr(vis, expr),
+            Node::Stmt(stmt) => check_stmt(vis, stmt),
+            Node::Item(_) => {
                 // We reached the top of the function, stop.
                 break;
             },
@@ -215,19 +212,19 @@ enum StopEarly {
 }
 
 fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> StopEarly {
-    if expr.id == vis.last_expr.id {
+    if expr.hir_id == vis.last_expr.hir_id {
         return StopEarly::KeepGoing;
     }
 
     match expr.node {
-        ExprKind::Array(_) |
-        ExprKind::Tup(_) |
-        ExprKind::MethodCall(..) |
-        ExprKind::Call(_, _) |
-        ExprKind::Assign(_, _) |
-        ExprKind::Index(_, _) |
-        ExprKind::Repeat(_, _) |
-        ExprKind::Struct(_, _, _) => {
+        ExprKind::Array(_)
+        | ExprKind::Tup(_)
+        | ExprKind::MethodCall(..)
+        | ExprKind::Call(_, _)
+        | ExprKind::Assign(_, _)
+        | ExprKind::Index(_, _)
+        | ExprKind::Repeat(_, _)
+        ExprKind::Struct(_, _, _) => {
             walk_expr(vis, expr);
         },
         ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
@@ -241,13 +238,12 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St
         ExprKind::Closure(_, _, _, _, _) => {
             // Either
             //
-            // * `var` is defined in the closure body, in which case we've
-            //   reached the top of the enclosing function and can stop, or
+            // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
+            //   function and can stop, or
             //
-            // * `var` is captured by the closure, in which case, because
-            //   evaluating a closure does not evaluate its body, we don't
-            //   necessarily have a write, so we need to stop to avoid
-            //   generating false positives.
+            // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
+            //   its body, we don't necessarily have a write, so we need to stop to avoid generating false
+            //   positives.
             //
             // This is also the only place we need to stop early (grrr).
             return StopEarly::Stop;
@@ -264,26 +260,22 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St
 
 fn check_stmt<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, stmt: &'tcx Stmt) -> StopEarly {
     match stmt.node {
-        StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => check_expr(vis, expr),
-        StmtKind::Decl(ref decl, _) => {
-            // If the declaration is of a local variable, check its initializer
-            // expression if it has one. Otherwise, keep going.
-            let local = match decl.node {
-                DeclKind::Local(ref local) => Some(local),
-                _ => None,
-            };
-            local
-                .and_then(|local| local.init.as_ref())
-                .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr))
-        },
+        StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => check_expr(vis, expr),
+        // If the declaration is of a local variable, check its initializer
+        // expression if it has one. Otherwise, keep going.
+        StmtKind::Local(ref local) => local
+            .init
+            .as_ref()
+            .map_or(StopEarly::KeepGoing, |expr| check_expr(vis, expr)),
+        _ => StopEarly::KeepGoing,
     }
 }
 
 /// A visitor that looks for reads from a variable.
 struct ReadVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    /// The id of the variable we're looking for.
-    var: ast::NodeId,
+    /// The ID of the variable we're looking for.
+    var: HirId,
     /// The expressions where the write to the variable occurred (for reporting
     /// in the lint).
     write_expr: &'tcx Expr,
@@ -294,7 +286,7 @@ struct ReadVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr) {
-        if expr.id == self.last_expr.id {
+        if expr.hir_id == self.last_expr.hir_id {
             return;
         }
 
@@ -303,7 +295,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                 if_chain! {
                     if let QPath::Resolved(None, ref path) = *qpath;
                     if path.segments.len() == 1;
-                    if let def::Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
+                    if let def::Res::Local(local_id) = self.cx.tables.qpath_res(qpath, expr.hir_id);
                     if local_id == self.var;
                     // Check that this is a read, not a write.
                     if !is_in_assignment_position(self.cx, expr);
@@ -347,11 +339,11 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-/// Returns true if `expr` is the LHS of an assignment, like `expr = ...`.
+/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
 fn is_in_assignment_position(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
     if let Some(parent) = get_parent_expr(cx, expr) {
         if let ExprKind::Assign(ref lhs, _) = parent.node {
-            return lhs.id == expr.id;
+            return lhs.hir_id == expr.hir_id;
         }
     }
     false
index 2c673fdfe3f70b7a564bbbc1b07340b0999aed9e..5f631237885ce5a80f71d44ebd212252cd78865b 100644 (file)
@@ -1,52 +1,47 @@
-use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::span_lint_and_sugg;
 use if_chain::if_chain;
-use rustc::ty::TypeVariants;
+use rustc::hir;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use std::f32;
 use std::f64;
 use std::fmt;
 use syntax::ast::*;
 use syntax_pos::symbol::Symbol;
-use crate::utils::span_lint_and_sugg;
 
-/// **What it does:** Checks for float literals with a precision greater
-/// than that supported by the underlying type
-///
-/// **Why is this bad?** Rust will truncate the literal silently.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// // Bad
-///    let v: f32 = 0.123_456_789_9;
-///    println!("{}", v); //  0.123_456_789
-///
-/// // Good
-///    let v: f64 = 0.123_456_789_9;
-///    println!("{}", v); //  0.123_456_789_9
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for float literals with a precision greater
+    /// than that supported by the underlying type
+    ///
+    /// **Why is this bad?** Rust will truncate the literal silently.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let v: f32 = 0.123_456_789_9;
+    /// println!("{}", v); //  0.123_456_789
+    ///
+    /// // Good
+    /// let v: f64 = 0.123_456_789_9;
+    /// println!("{}", v); //  0.123_456_789_9
+    /// ```
     pub EXCESSIVE_PRECISION,
     style,
     "excessive precision for float literal"
 }
 
-pub struct ExcessivePrecision;
-
-impl LintPass for ExcessivePrecision {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(EXCESSIVE_PRECISION)
-    }
-}
+declare_lint_pass!(ExcessivePrecision => [EXCESSIVE_PRECISION]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
         if_chain! {
             let ty = cx.tables.expr_ty(expr);
-            if let TypeVariants::TyFloat(fty) = ty.sty;
+            if let ty::Float(fty) = ty.sty;
             if let hir::ExprKind::Lit(ref lit) = expr.node;
             if let LitKind::Float(sym, _) | LitKind::FloatUnsuffixed(sym) = lit.node;
             if let Some(sugg) = self.check(sym, fty);
@@ -58,6 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                     "float has excessive precision",
                     "consider changing the type or truncating it to",
                     sugg,
+                    Applicability::MachineApplicable,
                 );
             }
         }
@@ -66,11 +62,11 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
 
 impl ExcessivePrecision {
     // None if nothing to lint, Some(suggestion) if lint necessary
-    fn check(&self, sym: Symbol, fty: FloatTy) -> Option<String> {
+    fn check(self, sym: Symbol, fty: FloatTy) -> Option<String> {
         let max = max_digits(fty);
         let sym_str = sym.as_str();
         if dot_zero_exclusion(&sym_str) {
-            return None
+            return None;
         }
         // Try to bail out if the float is for sure fine.
         // If its within the 2 decimal digits of being out of precision we
@@ -98,17 +94,17 @@ fn check(&self, sym: Symbol, fty: FloatTy) -> Option<String> {
     }
 }
 
-/// Should we exclude the float because it has a .0 suffix
-/// Ex 1_000_000_000.0
+/// Should we exclude the float because it has a `.0` or `.` suffix
+/// Ex `1_000_000_000.0`
+/// Ex `1_000_000_000.`
 fn dot_zero_exclusion(s: &str) -> bool {
     if let Some(after_dec) = s.split('.').nth(1) {
-        let mut decpart = after_dec
-            .chars()
-            .take_while(|c| *c != 'e' || *c != 'E');
+        let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');
 
         match decpart.next() {
             Some('0') => decpart.count() == 0,
-            _ => false,
+            Some(_) => false,
+            None => true,
         }
     } else {
         false
@@ -124,10 +120,10 @@ fn max_digits(fty: FloatTy) -> u32 {
 
 /// Counts the digits excluding leading zeros
 fn count_digits(s: &str) -> usize {
-    // Note that s does not contain the f32/64 suffix
+    // Note that s does not contain the f32/64 suffix, and underscores have been stripped
     s.chars()
-        .filter(|c| *c != '-' || *c != '.')
-        .take_while(|c| *c != 'e' || *c != 'E')
+        .filter(|c| *c != '-' && *c != '.')
+        .take_while(|c| *c != 'e' && *c != 'E')
         .fold(0, |count, c| {
             // leading zeros
             if c == '0' && count == 0 {
@@ -154,7 +150,9 @@ fn new(s: &str) -> Self {
             .unwrap_or(FloatFormat::Normal)
     }
     fn format<T>(&self, f: T) -> String
-    where T: fmt::UpperExp + fmt::LowerExp + fmt::Display {
+    where
+        T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
+    {
         match self {
             FloatFormat::LowerExp => format!("{:e}", f),
             FloatFormat::UpperExp => format!("{:E}", f),
index 22e6834ee884358cb878eebf4d7b4bc257d2c94f..11f2770333fb0e826ab1cea11557afe845a9d84b 100644 (file)
@@ -1,58 +1,51 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{is_expn_of, match_def_path, paths, resolve_node, span_lint, span_lint_and_sugg};
 use if_chain::if_chain;
-use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint};
-use crate::utils::opt_def_id;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::LitKind;
 
-/// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
-/// replaced with `(e)print!()` / `(e)println!()`
-///
-/// **Why is this bad?** Using `(e)println! is clearer and more concise
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// // this would be clearer as `eprintln!("foo: {:?}", bar);`
-/// writeln!(&mut io::stderr(), "foo: {:?}", bar).unwrap();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
+    /// replaced with `(e)print!()` / `(e)println!()`
+    ///
+    /// **Why is this bad?** Using `(e)println! is clearer and more concise
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // this would be clearer as `eprintln!("foo: {:?}", bar);`
+    /// writeln!(&mut io::stderr(), "foo: {:?}", bar).unwrap();
+    /// ```
     pub EXPLICIT_WRITE,
     complexity,
-    "using the `write!()` family of functions instead of the `print!()` family \
-     of functions, when using the latter would work"
+    "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct Pass;
+declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(EXPLICIT_WRITE)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitWrite {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
             // match call to unwrap
             if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args) = expr.node;
-            if unwrap_fun.ident.name == "unwrap";
+            if unwrap_fun.ident.name == *sym::unwrap;
             // match call to write_fmt
             if unwrap_args.len() > 0;
             if let ExprKind::MethodCall(ref write_fun, _, ref write_args) =
                 unwrap_args[0].node;
-            if write_fun.ident.name == "write_fmt";
+            if write_fun.ident.name == *sym::write_fmt;
             // match calls to std::io::stdout() / std::io::stderr ()
             if write_args.len() > 0;
             if let ExprKind::Call(ref dest_fun, _) = write_args[0].node;
             if let ExprKind::Path(ref qpath) = dest_fun.node;
-            if let Some(dest_fun_id) =
-                opt_def_id(resolve_node(cx, qpath, dest_fun.hir_id));
-            if let Some(dest_name) = if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stdout"]) {
+            if let Some(dest_fun_id) = resolve_node(cx, qpath, dest_fun.hir_id).opt_def_id();
+            if let Some(dest_name) = if match_def_path(cx, dest_fun_id, &*paths::STDOUT) {
                 Some("stdout")
-            } else if match_def_path(cx.tcx, dest_fun_id, &["std", "io", "stdio", "stderr"]) {
+            } else if match_def_path(cx, dest_fun_id, &*paths::STDERR) {
                 Some("stderr")
             } else {
                 None
@@ -61,9 +54,9 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 let write_span = unwrap_args[0].span;
                 let calling_macro =
                     // ordering is important here, since `writeln!` uses `write!` internally
-                    if is_expn_of(write_span, "writeln").is_some() {
+                    if is_expn_of(write_span, *sym::writeln).is_some() {
                         Some("writeln")
-                    } else if is_expn_of(write_span, "write").is_some() {
+                    } else if is_expn_of(write_span, *sym::write).is_some() {
                         Some("write")
                     } else {
                         None
@@ -73,32 +66,85 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 } else {
                     ""
                 };
-                if let Some(macro_name) = calling_macro {
-                    span_lint(
-                        cx,
-                        EXPLICIT_WRITE,
-                        expr.span,
-                        &format!(
-                            "use of `{}!({}(), ...).unwrap()`. Consider using `{}{}!` instead",
-                            macro_name,
-                            dest_name,
-                            prefix,
-                            macro_name.replace("write", "print")
-                        )
-                    );
+
+                // We need to remove the last trailing newline from the string because the
+                // underlying `fmt::write` function doesn't know whether `println!` or `print!` was
+                // used.
+                if let Some(mut write_output) = write_output_string(write_args) {
+                    if write_output.ends_with('\n') {
+                        write_output.pop();
+                    }
+
+                    if let Some(macro_name) = calling_macro {
+                        span_lint_and_sugg(
+                            cx,
+                            EXPLICIT_WRITE,
+                            expr.span,
+                            &format!(
+                                "use of `{}!({}(), ...).unwrap()`",
+                                macro_name,
+                                dest_name
+                            ),
+                            "try this",
+                            format!("{}{}!(\"{}\")", prefix, macro_name.replace("write", "print"), write_output.escape_default()),
+                            Applicability::MachineApplicable
+                        );
+                    } else {
+                        span_lint_and_sugg(
+                            cx,
+                            EXPLICIT_WRITE,
+                            expr.span,
+                            &format!("use of `{}().write_fmt(...).unwrap()`", dest_name),
+                            "try this",
+                            format!("{}print!(\"{}\")", prefix, write_output.escape_default()),
+                            Applicability::MachineApplicable
+                        );
+                    }
                 } else {
-                    span_lint(
-                        cx,
-                        EXPLICIT_WRITE,
-                        expr.span,
-                        &format!(
-                            "use of `{}().write_fmt(...).unwrap()`. Consider using `{}print!` instead",
-                            dest_name,
-                            prefix,
-                        )
-                    );
+                    // We don't have a proper suggestion
+                    if let Some(macro_name) = calling_macro {
+                        span_lint(
+                            cx,
+                            EXPLICIT_WRITE,
+                            expr.span,
+                            &format!(
+                                "use of `{}!({}(), ...).unwrap()`. Consider using `{}{}!` instead",
+                                macro_name,
+                                dest_name,
+                                prefix,
+                                macro_name.replace("write", "print")
+                            )
+                        );
+                    } else {
+                        span_lint(
+                            cx,
+                            EXPLICIT_WRITE,
+                            expr.span,
+                            &format!("use of `{}().write_fmt(...).unwrap()`. Consider using `{}print!` instead", dest_name, prefix),
+                        );
+                    }
                 }
+
             }
         }
     }
 }
+
+// Extract the output string from the given `write_args`.
+fn write_output_string(write_args: &HirVec<Expr>) -> Option<String> {
+    if_chain! {
+        // Obtain the string that should be printed
+        if write_args.len() > 1;
+        if let ExprKind::Call(_, ref output_args) = write_args[1].node;
+        if output_args.len() > 0;
+        if let ExprKind::AddrOf(_, ref output_string_expr) = output_args[0].node;
+        if let ExprKind::Array(ref string_exprs) = output_string_expr.node;
+        if string_exprs.len() > 0;
+        if let ExprKind::Lit(ref lit) = string_exprs[0].node;
+        if let LitKind::Str(ref write_output, _) = lit.node;
+        then {
+            return Some(write_output.to_string())
+        }
+    }
+    None
+}
index 3db644911d78a75fd1dadb10c53de8ce3b2dd2b0..ee1b888cb07d536dd021b22202ba26cf4e42ad92 100644 (file)
@@ -1,49 +1,45 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
+use crate::utils::sym;
+use crate::utils::{is_expn_of, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty};
 use if_chain::if_chain;
 use rustc::hir;
-use rustc::ty;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::symbol::Symbol;
 use syntax_pos::Span;
-use crate::utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, is_expn_of, opt_def_id};
-use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
 
-/// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
-///
-/// **Why is this bad?** `TryFrom` should be used if there's a possibility of failure.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct Foo(i32);
-/// impl From<String> for Foo {
-///     fn from(s: String) -> Self {
-///         Foo(s.parse().unwrap())
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
+    ///
+    /// **Why is this bad?** `TryFrom` should be used if there's a possibility of failure.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct Foo(i32);
+    /// impl From<String> for Foo {
+    ///     fn from(s: String) -> Self {
+    ///         Foo(s.parse().unwrap())
+    ///     }
+    /// }
+    /// ```
     pub FALLIBLE_IMPL_FROM,
     nursery,
     "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`"
 }
 
-pub struct FallibleImplFrom;
-
-impl LintPass for FallibleImplFrom {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(FALLIBLE_IMPL_FROM)
-    }
-}
+declare_lint_pass!(FallibleImplFrom => [FALLIBLE_IMPL_FROM]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
         // check for `impl From<???> for ..`
-        let impl_def_id = cx.tcx.hir.local_def_id(item.id);
+        let impl_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
         if_chain! {
             if let hir::ItemKind::Impl(.., ref impl_items) = item.node;
             if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id);
-            if match_def_path(cx.tcx, impl_trait_ref.def_id, &FROM_TRAIT);
+            if match_def_path(cx, impl_trait_ref.def_id, &*FROM_TRAIT);
             then {
                 lint_impl_body(cx, item.span, impl_items);
             }
@@ -52,11 +48,11 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
 }
 
 fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_items: &hir::HirVec<hir::ImplItemRef>) {
-    use rustc::hir::*;
     use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
+    use rustc::hir::*;
 
     struct FindPanicUnwrap<'a, 'tcx: 'a> {
-        tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+        lcx: &'a LateContext<'a, 'tcx>,
         tables: &'tcx ty::TypeckTables<'tcx>,
         result: Vec<Span>,
     }
@@ -67,19 +63,19 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
             if_chain! {
                 if let ExprKind::Call(ref func_expr, _) = expr.node;
                 if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.node;
-                if let Some(path_def_id) = opt_def_id(path.def);
-                if match_def_path(self.tcx, path_def_id, &BEGIN_PANIC) ||
-                    match_def_path(self.tcx, path_def_id, &BEGIN_PANIC_FMT);
-                if is_expn_of(expr.span, "unreachable").is_none();
+                if let Some(path_def_id) = path.res.opt_def_id();
+                if match_def_path(self.lcx, path_def_id, &*BEGIN_PANIC) ||
+                    match_def_path(self.lcx, path_def_id, &*BEGIN_PANIC_FMT);
+                if is_expn_of(expr.span, *sym::unreachable).is_none();
                 then {
                     self.result.push(expr.span);
                 }
             }
 
             // check for `unwrap`
-            if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
+            if let Some(arglists) = method_chain_args(expr, &[*sym::unwrap]) {
                 let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
-                if match_type(self.tcx, reciever_ty, &OPTION) || match_type(self.tcx, reciever_ty, &RESULT) {
+                if match_type(self.lcx, reciever_ty, &*OPTION) || match_type(self.lcx, reciever_ty, &*RESULT) {
                     self.result.push(expr.span);
                 }
             }
@@ -95,15 +91,15 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
     for impl_item in impl_items {
         if_chain! {
-            if impl_item.ident.name == "from";
+            if impl_item.ident.name == *sym::from;
             if let ImplItemKind::Method(_, body_id) =
-                cx.tcx.hir.impl_item(impl_item.id).node;
+                cx.tcx.hir().impl_item(impl_item.id).node;
             then {
                 // check the body for `begin_panic` or `unwrap`
-                let body = cx.tcx.hir.body(body_id);
-                let impl_item_def_id = cx.tcx.hir.local_def_id(impl_item.id.node_id);
+                let body = cx.tcx.hir().body(body_id);
+                let impl_item_def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.id.hir_id);
                 let mut fpu = FindPanicUnwrap {
-                    tcx: cx.tcx,
+                    lcx: cx,
                     tables: cx.tcx.typeck_tables_of(impl_item_def_id),
                     result: Vec::new(),
                 };
@@ -128,9 +124,9 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-fn match_type(tcx: ty::TyCtxt<'_, '_, '_>, ty: ty::Ty<'_>, path: &[&str]) -> bool {
+fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[Symbol]) -> bool {
     match ty.sty {
-        ty::TyAdt(adt, _) => match_def_path(tcx, adt.did, path),
+        ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
         _ => false,
     }
 }
index 80fc4c3acfe48be0e728a702d180732b78bd85f7..cb9e486a7093c02ca7c2c5373b44e27f5bc9fc48 100644 (file)
@@ -1,77 +1,90 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::paths;
+use crate::utils::sym;
+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,
+};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ast::LitKind;
-use syntax_pos::Span;
-use crate::utils::paths;
-use crate::utils::{in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for the use of `format!("string literal with no
-/// argument")` and `format!("{}", foo)` where `foo` is a string.
-///
-/// **Why is this bad?** There is no point of doing that. `format!("too")` can
-/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
-/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
-/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
-/// if `foo: &str`.
-///
-/// **Known problems:** None.
-///
-/// **Examples:**
-/// ```rust
-/// format!("foo")
-/// format!("{}", foo)
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for the use of `format!("string literal with no
+    /// argument")` and `format!("{}", foo)` where `foo` is a string.
+    ///
+    /// **Why is this bad?** There is no point of doing that. `format!("foo")` can
+    /// be replaced by `"foo".to_owned()` if you really need a `String`. The even
+    /// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
+    /// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
+    /// if `foo: &str`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// format!("foo")
+    /// format!("{}", foo)
+    /// ```
     pub USELESS_FORMAT,
     complexity,
     "useless use of `format!`"
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array![USELESS_FORMAT]
-    }
-}
+declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+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(span) {
+        if let Some(span) = is_expn_of(expr.span, *sym::format) {
+            if in_macro_or_desugar(span) {
                 return;
             }
             match expr.node {
-
                 // `format!("{}", foo)` expansion
                 ExprKind::Call(ref fun, ref args) => {
                     if_chain! {
                         if let ExprKind::Path(ref qpath) = fun.node;
-                        if args.len() == 3;
-                        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
-                        if match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1FORMATTED);
+                        if let Some(fun_def_id) = resolve_node(cx, qpath, fun.hir_id).opt_def_id();
+                        let new_v1 = match_def_path(cx, fun_def_id, &*paths::FMT_ARGUMENTS_NEWV1);
+                        let new_v1_fmt = match_def_path(cx,
+                            fun_def_id,
+                            &*paths::FMT_ARGUMENTS_NEWV1FORMATTED
+                        );
+                        if new_v1 || new_v1_fmt;
                         if check_single_piece(&args[0]);
                         if let Some(format_arg) = get_single_string_arg(cx, &args[1]);
-                        if check_unformatted(&args[2]);
+                        if new_v1 || check_unformatted(&args[2]);
+                        if let ExprKind::AddrOf(_, ref format_arg) = format_arg.node;
                         then {
-                            let sugg = format!("{}.to_string()", snippet(cx, format_arg, "<arg>").into_owned());
-                            span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
-                                db.span_suggestion(expr.span, "consider using .to_string()", sugg);
-                            });
+                            let (message, sugg) = if_chain! {
+                                if let ExprKind::MethodCall(ref path, _, _) = format_arg.node;
+                                if path.ident.as_interned_str() == "to_string";
+                                then {
+                                    ("`to_string()` is enough",
+                                    snippet(cx, format_arg.span, "<arg>").to_string())
+                                } else {
+                                    ("consider using .to_string()",
+                                    format!("{}.to_string()", snippet(cx, format_arg.span, "<arg>")))
+                                }
+                            };
+
+                            span_useless_format(cx, span, message, sugg);
                         }
                     }
                 },
                 // `format!("foo")` expansion contains `match () { () => [], }`
-                ExprKind::Match(ref matchee, _, _) => if let ExprKind::Tup(ref tup) = matchee.node {
-                    if tup.is_empty() {
-                        let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
-                        span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
-                            db.span_suggestion(span, "consider using .to_string()", sugg);
-                        });
+                ExprKind::Match(ref matchee, _, _) => {
+                    if let ExprKind::Tup(ref tup) = matchee.node {
+                        if tup.is_empty() {
+                            let actual_snippet = snippet(cx, expr.span, "<expr>").to_string();
+                            let actual_snippet = actual_snippet.replace("{{}}", "{}");
+                            let sugg = format!("{}.to_string()", actual_snippet);
+                            span_useless_format(cx, span, "consider using .to_string()", sugg);
+                        }
                     }
                 },
                 _ => (),
@@ -80,6 +93,25 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
+fn span_useless_format<'a, 'tcx: 'a, T: LintContext<'tcx>>(cx: &'a T, span: Span, help: &str, mut sugg: String) {
+    let to_replace = span.source_callsite();
+
+    // The callsite span contains the statement semicolon for some reason.
+    let snippet = snippet(cx, to_replace, "..");
+    if snippet.ends_with(';') {
+        sugg.push(';');
+    }
+
+    span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
+        db.span_suggestion(
+            to_replace,
+            help,
+            sugg,
+            Applicability::MachineApplicable, // snippet
+        );
+    });
+}
+
 /// Checks if the expressions matches `&[""]`
 fn check_single_piece(expr: &Expr) -> bool {
     if_chain! {
@@ -103,9 +135,9 @@ fn check_single_piece(expr: &Expr) -> bool {
 /// ::std::fmt::Display::fmt)],
 /// }
 /// ```
-/// and that type of `__arg0` is `&str` or `String`
-/// then returns the span of first element of the matched tuple
-fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Span> {
+/// and that the type of `__arg0` is `&str` or `String`,
+/// then returns the span of first element of the matched tuple.
+fn get_single_string_arg<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<&'a Expr> {
     if_chain! {
         if let ExprKind::AddrOf(_, ref expr) = expr.node;
         if let ExprKind::Match(ref match_expr, ref arms, _) = expr.node;
@@ -118,13 +150,13 @@ fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Span>
         if let ExprKind::Call(_, ref args) = exprs[0].node;
         if args.len() == 2;
         if let ExprKind::Path(ref qpath) = args[1].node;
-        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, args[1].hir_id));
-        if match_def_path(cx.tcx, fun_def_id, &paths::DISPLAY_FMT_METHOD);
+        if let Some(fun_def_id) = resolve_node(cx, qpath, args[1].hir_id).opt_def_id();
+        if match_def_path(cx, fun_def_id, &*paths::DISPLAY_FMT_METHOD);
         then {
             let ty = walk_ptrs_ty(cx.tables.pat_ty(&pat[0]));
-            if ty.sty == ty::TyStr || match_type(cx, ty, &paths::STRING) {
+            if ty.sty == ty::Str || match_type(cx, ty, &*paths::STRING) {
                 if let ExprKind::Tup(ref values) = match_expr.node {
-                    return Some(values[0].span);
+                    return Some(&values[0]);
                 }
             }
         }
@@ -149,11 +181,14 @@ fn check_unformatted(expr: &Expr) -> bool {
         if let ExprKind::Array(ref exprs) = expr.node;
         if exprs.len() == 1;
         if let ExprKind::Struct(_, ref fields, _) = exprs[0].node;
-        if let Some(format_field) = fields.iter().find(|f| f.ident.name == "format");
+        if let Some(format_field) = fields.iter().find(|f| f.ident.name == *sym::format);
         if let ExprKind::Struct(_, ref fields, _) = format_field.expr.node;
-        if let Some(align_field) = fields.iter().find(|f| f.ident.name == "width");
-        if let ExprKind::Path(ref qpath) = align_field.expr.node;
-        if last_path_segment(qpath).ident.name == "Implied";
+        if let Some(width_field) = fields.iter().find(|f| f.ident.name == *sym::width);
+        if let ExprKind::Path(ref width_qpath) = width_field.expr.node;
+        if last_path_segment(width_qpath).ident.name == *sym::Implied;
+        if let Some(precision_field) = fields.iter().find(|f| f.ident.name == *sym::precision);
+        if let ExprKind::Path(ref precision_path) = precision_field.expr.node;
+        if last_path_segment(precision_path).ident.name == *sym::Implied;
         then {
             return true;
         }
index 60001c792c0b41640ef5e0ededccf247cca773b6..5916a0659500cf48c0fee38697e7ff1c6f3f662c 100644 (file)
@@ -1,94 +1,97 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{differing_macro_contexts, in_macro_or_desugar, 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};
 use syntax::ast;
-use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
 use syntax::ptr::P;
 
-/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
-/// operators.
-///
-/// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
-/// confusing.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
+    /// operators.
+    ///
+    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
+    /// confusing.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
+    /// ```
     pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
     style,
     "suspicious formatting of `*=`, `-=` or `!=`"
 }
 
-/// **What it does:** Checks for formatting of `else if`. It lints if the `else`
-/// and `if` are not on the same line or the `else` seems to be missing.
-///
-/// **Why is this bad?** This is probably some refactoring remnant, even if the
-/// code is correct, it might look confusing.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// if foo {
-/// } if bar { // looks like an `else` is missing here
-/// }
-///
-/// if foo {
-/// } else
-///
-/// if bar { // this is the `else` block of the previous `if`, but should it be?
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
+    /// is followed immediately by a newline or the `else` seems to be missing.
+    ///
+    /// **Why is this bad?** This is probably some refactoring remnant, even if the
+    /// code is correct, it might look confusing.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// if foo {
+    /// } { // looks like an `else` is missing here
+    /// }
+    ///
+    /// if foo {
+    /// } if bar { // looks like an `else` is missing here
+    /// }
+    ///
+    /// if foo {
+    /// } else
+    ///
+    /// { // this is the `else` block of the previous `if`, but should it be?
+    /// }
+    ///
+    /// if foo {
+    /// } else
+    ///
+    /// if bar { // this is the `else` block of the previous `if`, but should it be?
+    /// }
+    /// ```
     pub SUSPICIOUS_ELSE_FORMATTING,
     style,
-    "suspicious formatting of `else if`"
+    "suspicious formatting of `else`"
 }
 
-/// **What it does:** Checks for possible missing comma in an array. It lints if
-/// an array element is a binary operator expression and it lies on two lines.
-///
-/// **Why is this bad?** This could lead to unexpected results.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// let a = &[
-///     -1, -2, -3 // <= no comma here
-///     -4, -5, -6
-/// ];
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for possible missing comma in an array. It lints if
+    /// an array element is a binary operator expression and it lies on two lines.
+    ///
+    /// **Why is this bad?** This could lead to unexpected results.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// let a = &[
+    ///     -1, -2, -3 // <= no comma here
+    ///     -4, -5, -6
+    /// ];
+    /// ```
     pub POSSIBLE_MISSING_COMMA,
     correctness,
     "possible missing comma in array"
 }
 
-
-#[derive(Copy, Clone)]
-pub struct Formatting;
-
-impl LintPass for Formatting {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            SUSPICIOUS_ASSIGNMENT_FORMATTING,
-            SUSPICIOUS_ELSE_FORMATTING,
-            POSSIBLE_MISSING_COMMA
-        )
-    }
-}
+declare_lint_pass!(Formatting => [
+    SUSPICIOUS_ASSIGNMENT_FORMATTING,
+    SUSPICIOUS_ELSE_FORMATTING,
+    POSSIBLE_MISSING_COMMA
+]);
 
 impl EarlyLintPass for Formatting {
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
         for w in block.stmts.windows(2) {
             match (&w[0].node, &w[1].node) {
-                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) |
-                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
-                    check_consecutive_ifs(cx, first, second);
+                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
+                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
+                    check_missing_else(cx, first, second);
                 },
                 _ => (),
             }
@@ -97,7 +100,7 @@ fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         check_assign(cx, expr);
-        check_else_if(cx, expr);
+        check_else(cx, expr);
         check_array(cx, expr);
     }
 }
@@ -105,7 +108,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
 /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
 fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
-        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro(lhs.span) {
+        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro_or_desugar(lhs.span) {
             let eq_span = lhs.span.between(rhs.span);
             if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                 if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
@@ -131,44 +134,56 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     }
 }
 
-/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else if`.
-fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
-    if let Some((then, &Some(ref else_))) = unsugar_if(expr) {
-        if unsugar_if(else_).is_some() && !differing_macro_contexts(then.span, else_.span) && !in_macro(then.span) {
-            // this will be a span from the closing ‘}’ of the “then” block (excluding) to
-            // the
-            // “if” of the “else if” block (excluding)
-            let else_span = then.span.between(else_.span);
-
-            // the snippet should look like " else \n    " with maybe comments anywhere
-            // it’s bad when there is a ‘\n’ after the “else”
-            if let Some(else_snippet) = snippet_opt(cx, else_span) {
-                let else_pos = else_snippet
-                    .find("else")
-                    .expect("there must be a `else` here");
-
-                if else_snippet[else_pos..].contains('\n') {
-                    span_note_and_lint(
-                        cx,
-                        SUSPICIOUS_ELSE_FORMATTING,
-                        else_span,
-                        "this is an `else if` but the formatting might hide it",
-                        else_span,
-                        "to remove this lint, remove the `else` or remove the new line between `else` \
-                         and `if`",
-                    );
-                }
-            }
+/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
+fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
+    if_chain! {
+        if let Some((then, &Some(ref else_))) = unsugar_if(expr);
+        if is_block(else_) || unsugar_if(else_).is_some();
+        if !differing_macro_contexts(then.span, else_.span);
+        if !in_macro_or_desugar(then.span) && !in_external_macro(cx.sess, expr.span);
+
+        // workaround for rust-lang/rust#43081
+        if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
+
+        // this will be a span from the closing ‘}’ of the “then” block (excluding) to
+        // the “if” of the “else if” block (excluding)
+        let else_span = then.span.between(else_.span);
+
+        // the snippet should look like " else \n    " with maybe comments anywhere
+        // it’s bad when there is a ‘\n’ after the “else”
+        if let Some(else_snippet) = snippet_opt(cx, else_span);
+        if let Some(else_pos) = else_snippet.find("else");
+        if else_snippet[else_pos..].contains('\n');
+        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };
+
+        then {
+            span_note_and_lint(
+                cx,
+                SUSPICIOUS_ELSE_FORMATTING,
+                else_span,
+                &format!("this is an `else {}` but the formatting might hide it", else_desc),
+                else_span,
+                &format!(
+                    "to remove this lint, remove the `else` or remove the new line between \
+                     `else` and `{}`",
+                    else_desc,
+                ),
+            );
         }
     }
 }
 
+fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
+    // &, *, -
+    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
+}
+
 /// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
 fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     if let ast::ExprKind::Array(ref array) = expr.node {
         for element in array {
             if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
-                if !differing_macro_contexts(lhs.span, op.span) {
+                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                     let space_span = lhs.span.between(op.span);
                     if let Some(space_snippet) = snippet_opt(cx, space_span) {
                         let lint_span = lhs.span.with_lo(lhs.span.hi());
@@ -189,30 +204,47 @@ fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     }
 }
 
-/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
-fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
-    if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some()
-        && unsugar_if(second).is_some()
+fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
+    if !differing_macro_contexts(first.span, second.span)
+        && !in_macro_or_desugar(first.span)
+        && unsugar_if(first).is_some()
+        && (is_block(second) || unsugar_if(second).is_some())
     {
         // where the else would be
         let else_span = first.span.between(second.span);
 
         if let Some(else_snippet) = snippet_opt(cx, else_span) {
             if !else_snippet.contains('\n') {
+                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
+                    ("an `else if`", "the second `if`")
+                } else {
+                    ("an `else {..}`", "the next block")
+                };
+
                 span_note_and_lint(
                     cx,
                     SUSPICIOUS_ELSE_FORMATTING,
                     else_span,
-                    "this looks like an `else if` but the `else` is missing",
+                    &format!("this looks like {} but the `else` is missing", looks_like),
                     else_span,
-                    "to remove this lint, add the missing `else` or add a new line before the second \
-                     `if`",
+                    &format!(
+                        "to remove this lint, add the missing `else` or add a new line before {}",
+                        next_thing,
+                    ),
                 );
             }
         }
     }
 }
 
+fn is_block(expr: &ast::Expr) -> bool {
+    if let ast::ExprKind::Block(..) = expr.node {
+        true
+    } else {
+        false
+    }
+}
+
 /// Match `if` or `if let` expressions and return the `then` and `else` block.
 fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
     match expr.node {
index 8903766c330b4636dfc488d446ce4856bcd3bb4f..84cafd1056ce8ede8af661bd1dc87da7500d922e 100644 (file)
@@ -1,56 +1,83 @@
+use std::convert::TryFrom;
+
+use crate::utils::{iter_input_pats, snippet, snippet_opt, span_lint, type_is_unsafe_function};
 use matches::matches;
-use rustc::hir::intravisit;
 use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::hir::def::Res;
+use rustc::hir::intravisit;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
-use rustc::hir::def::Def;
-use std::collections::HashSet;
-use syntax::ast;
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_target::spec::abi::Abi;
-use syntax::codemap::Span;
-use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function};
-
-/// **What it does:** Checks for functions with too many parameters.
-///
-/// **Why is this bad?** Functions with lots of parameters are considered bad
-/// style and reduce readability (“what does the 5th parameter mean?”). Consider
-/// grouping some parameters into a new type.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b:
-/// f32) { .. }
-/// ```
+use syntax::source_map::{BytePos, Span};
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for functions with too many parameters.
+    ///
+    /// **Why is this bad?** Functions with lots of parameters are considered bad
+    /// style and reduce readability (“what does the 5th parameter mean?”). Consider
+    /// grouping some parameters into a new type.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
+    ///     ..
+    /// }
+    /// ```
     pub TOO_MANY_ARGUMENTS,
     complexity,
     "functions with too many arguments"
 }
 
-/// **What it does:** Checks for public functions that dereferences raw pointer
-/// arguments but are not marked unsafe.
-///
-/// **Why is this bad?** The function should probably be marked `unsafe`, since
-/// for an arbitrary raw pointer, there is no way of telling for sure if it is
-/// valid.
-///
-/// **Known problems:**
-///
-/// * It does not check functions recursively so if the pointer is passed to a
-/// private non-`unsafe` function which does the dereferencing, the lint won't
-/// trigger.
-/// * It only checks for arguments whose type are raw pointers, not raw pointers
-/// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
-/// `some_argument.get_raw_ptr()`).
-///
-/// **Example:**
-/// ```rust
-/// pub fn foo(x: *const u8) { println!("{}", unsafe { *x }); }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for functions with a large amount of lines.
+    ///
+    /// **Why is this bad?** Functions with a lot of lines are harder to understand
+    /// due to having to look at a larger amount of code to understand what the
+    /// function is doing. Consider splitting the body of the function into
+    /// multiple functions.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ``` rust
+    /// fn im_too_long() {
+    /// println!("");
+    /// // ... 100 more LoC
+    /// println!("");
+    /// }
+    /// ```
+    pub TOO_MANY_LINES,
+    pedantic,
+    "functions with too many lines"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for public functions that dereferences raw pointer
+    /// arguments but are not marked unsafe.
+    ///
+    /// **Why is this bad?** The function should probably be marked `unsafe`, since
+    /// for an arbitrary raw pointer, there is no way of telling for sure if it is
+    /// valid.
+    ///
+    /// **Known problems:**
+    ///
+    /// * It does not check functions recursively so if the pointer is passed to a
+    /// private non-`unsafe` function which does the dereferencing, the lint won't
+    /// trigger.
+    /// * It only checks for arguments whose type are raw pointers, not raw pointers
+    /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
+    /// `some_argument.get_raw_ptr()`).
+    ///
+    /// **Example:**
+    /// ```rust
+    /// pub fn foo(x: *const u8) {
+    ///     println!("{}", unsafe { *x });
+    /// }
+    /// ```
     pub NOT_UNSAFE_PTR_ARG_DEREF,
     correctness,
     "public functions dereferencing raw pointer arguments but not marked `unsafe`"
 #[derive(Copy, Clone)]
 pub struct Functions {
     threshold: u64,
+    max_lines: u64,
 }
 
 impl Functions {
-    pub fn new(threshold: u64) -> Self {
-        Self {
-            threshold,
-        }
+    pub fn new(threshold: u64, max_lines: u64) -> Self {
+        Self { threshold, max_lines }
     }
 }
 
-impl LintPass for Functions {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(TOO_MANY_ARGUMENTS, NOT_UNSAFE_PTR_ARG_DEREF)
-    }
-}
+impl_lint_pass!(Functions => [TOO_MANY_ARGUMENTS, TOO_MANY_LINES, NOT_UNSAFE_PTR_ARG_DEREF]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
     fn check_fn(
@@ -83,11 +105,13 @@ fn check_fn(
         decl: &'tcx hir::FnDecl,
         body: &'tcx hir::Body,
         span: Span,
-        nodeid: ast::NodeId,
+        hir_id: hir::HirId,
     ) {
-        use rustc::hir::map::Node::*;
-
-        let is_impl = if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(nodeid)) {
+        let is_impl = if let Some(hir::Node::Item(item)) = cx
+            .tcx
+            .hir()
+            .find_by_hir_id(cx.tcx.hir().get_parent_node_by_hir_id(hir_id))
+        {
             matches!(item.node, hir::ItemKind::Impl(_, _, _, _, Some(_), _, _))
         } else {
             false
@@ -103,13 +127,24 @@ fn check_fn(
         if !is_impl {
             // don't lint extern functions decls, it's not their fault either
             match kind {
-                hir::intravisit::FnKind::Method(_, &hir::MethodSig { header: hir::FnHeader { abi: Abi::Rust, .. }, .. }, _, _) |
-                hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => self.check_arg_number(cx, decl, span),
+                hir::intravisit::FnKind::Method(
+                    _,
+                    &hir::MethodSig {
+                        header: hir::FnHeader { abi: Abi::Rust, .. },
+                        ..
+                    },
+                    _,
+                    _,
+                )
+                | hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
+                    self.check_arg_number(cx, decl, span)
+                },
                 _ => {},
             }
         }
 
-        self.check_raw_ptr(cx, unsafety, decl, body, nodeid);
+        self.check_raw_ptr(cx, unsafety, decl, body, hir_id);
+        self.check_line_number(cx, span, body);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
@@ -120,8 +155,8 @@ fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Trai
             }
 
             if let hir::TraitMethod::Provided(eid) = *eid {
-                let body = cx.tcx.hir.body(eid);
-                self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.id);
+                let body = cx.tcx.hir().body(eid);
+                self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id);
             }
         }
     }
@@ -129,6 +164,19 @@ fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Trai
 
 impl<'a, 'tcx> Functions {
     fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) {
+        // Remove the function body from the span. We can't use `SourceMap::def_span` because the
+        // argument list might span multiple lines.
+        let span = if let Some(snippet) = snippet_opt(cx, span) {
+            let snippet = snippet.split('{').nth(0).unwrap_or("").trim_end();
+            if snippet.is_empty() {
+                span
+            } else {
+                span.with_hi(BytePos(span.lo().0 + u32::try_from(snippet.len()).unwrap()))
+            }
+        } else {
+            span
+        };
+
         let args = decl.inputs.len() as u64;
         if args > self.threshold {
             span_lint(
@@ -140,20 +188,86 @@ fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Sp
         }
     }
 
+    fn check_line_number(self, cx: &LateContext<'_, '_>, span: Span, body: &'tcx hir::Body) {
+        if in_external_macro(cx.sess(), span) {
+            return;
+        }
+
+        let code_snippet = snippet(cx, body.value.span, "..");
+        let mut line_count: u64 = 0;
+        let mut in_comment = false;
+        let mut code_in_line;
+
+        // Skip the surrounding function decl.
+        let start_brace_idx = match code_snippet.find('{') {
+            Some(i) => i + 1,
+            None => 0,
+        };
+        let end_brace_idx = match code_snippet.find('}') {
+            Some(i) => i,
+            None => code_snippet.len(),
+        };
+        let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+
+        for mut line in function_lines {
+            code_in_line = false;
+            loop {
+                line = line.trim_start();
+                if line.is_empty() {
+                    break;
+                }
+                if in_comment {
+                    match line.find("*/") {
+                        Some(i) => {
+                            line = &line[i + 2..];
+                            in_comment = false;
+                            continue;
+                        },
+                        None => break,
+                    }
+                } else {
+                    let multi_idx = match line.find("/*") {
+                        Some(i) => i,
+                        None => line.len(),
+                    };
+                    let single_idx = match line.find("//") {
+                        Some(i) => i,
+                        None => line.len(),
+                    };
+                    code_in_line |= multi_idx > 0 && single_idx > 0;
+                    // Implies multi_idx is below line.len()
+                    if multi_idx < single_idx {
+                        line = &line[multi_idx + 2..];
+                        in_comment = true;
+                        continue;
+                    }
+                    break;
+                }
+            }
+            if code_in_line {
+                line_count += 1;
+            }
+        }
+
+        if line_count > self.max_lines {
+            span_lint(cx, TOO_MANY_LINES, span, "This function has a large number of lines.")
+        }
+    }
+
     fn check_raw_ptr(
         self,
         cx: &LateContext<'a, 'tcx>,
         unsafety: hir::Unsafety,
         decl: &'tcx hir::FnDecl,
         body: &'tcx hir::Body,
-        nodeid: ast::NodeId,
+        hir_id: hir::HirId,
     ) {
         let expr = &body.value;
-        if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) {
+        if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(hir_id) {
             let raw_ptrs = iter_input_pats(decl, body)
                 .zip(decl.inputs.iter())
                 .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
-                .collect::<HashSet<_>>();
+                .collect::<FxHashSet<_>>();
 
             if !raw_ptrs.is_empty() {
                 let tables = cx.tcx.body_tables(body.id());
@@ -169,7 +283,7 @@ fn check_raw_ptr(
     }
 }
 
-fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<ast::NodeId> {
+fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<hir::HirId> {
     if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.node, &ty.node) {
         Some(id)
     } else {
@@ -179,7 +293,7 @@ fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<ast::NodeId> {
 
 struct DerefVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    ptrs: HashSet<ast::NodeId>,
+    ptrs: FxHashSet<hir::HirId>,
     tables: &'a ty::TypeckTables<'tcx>,
 }
 
@@ -196,7 +310,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
                 }
             },
             hir::ExprKind::MethodCall(_, _, ref args) => {
-                let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id();
+                let def_id = self.tables.type_dependent_def_id(expr.hir_id).unwrap();
                 let base_type = self.cx.tcx.type_of(def_id);
 
                 if type_is_unsafe_function(self.cx, base_type) {
@@ -219,7 +333,7 @@ fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'thi
 impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> {
     fn check_arg(&self, ptr: &hir::Expr) {
         if let hir::ExprKind::Path(ref qpath) = ptr.node {
-            if let Def::Local(id) = self.cx.tables.qpath_def(qpath, ptr.hir_id) {
+            if let Res::Local(id) = self.cx.tables.qpath_res(qpath, ptr.hir_id) {
                 if self.ptrs.contains(&id) {
                     span_lint(
                         self.cx,
index a0705f62544b6483155df66c46cfbddc6d132eea..5d15eb3341b379b734ba9ac23e6c0f6e389b843b 100644 (file)
@@ -1,45 +1,44 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{
+    in_macro_or_desugar, 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::*;
-use syntax::ast::NodeId;
-use crate::utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, span_lint_and_then};
-use crate::utils::{opt_def_id, paths, resolve_node};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for always-identical `Into`/`From` conversions.
-///
-/// **Why is this bad?** Redundant code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// // format!() returns a `String`
-/// let s: String = format!("hello").into();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for always-identical `Into`/`From`/`IntoIter` conversions.
+    ///
+    /// **Why is this bad?** Redundant code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // format!() returns a `String`
+    /// let s: String = format!("hello").into();
+    /// ```
     pub IDENTITY_CONVERSION,
     complexity,
-    "using always-identical `Into`/`From` conversions"
+    "using always-identical `Into`/`From`/`IntoIter` conversions"
 }
 
 #[derive(Default)]
 pub struct IdentityConversion {
-    try_desugar_arm: Vec<NodeId>,
+    try_desugar_arm: Vec<HirId>,
 }
 
-impl LintPass for IdentityConversion {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(IDENTITY_CONVERSION)
-    }
-}
+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(e.span) {
+        if in_macro_or_desugar(e.span) {
             return;
         }
 
-        if Some(&e.id) == self.try_desugar_arm.last() {
+        if Some(&e.hir_id) == self.try_desugar_arm.last() {
             return;
         }
 
@@ -50,36 +49,65 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                     _ => return,
                 };
                 if let ExprKind::Call(_, ref args) = e.node {
-                    self.try_desugar_arm.push(args[0].id);
+                    self.try_desugar_arm.push(args[0].hir_id);
                 } else {
                     return;
                 }
             },
 
             ExprKind::MethodCall(ref name, .., ref args) => {
-                if match_trait_method(cx, e, &paths::INTO[..]) && &*name.ident.as_str() == "into" {
+                if match_trait_method(cx, e, &*paths::INTO) && &*name.ident.as_str() == "into" {
+                    let a = cx.tables.expr_ty(e);
+                    let b = cx.tables.expr_ty(&args[0]);
+                    if same_tys(cx, a, b) {
+                        let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
+
+                        span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
+                            db.span_suggestion(
+                                e.span,
+                                "consider removing `.into()`",
+                                sugg,
+                                Applicability::MachineApplicable, // snippet
+                            );
+                        });
+                    }
+                }
+                if match_trait_method(cx, e, &*paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
                     let a = cx.tables.expr_ty(e);
                     let b = cx.tables.expr_ty(&args[0]);
                     if same_tys(cx, a, b) {
                         let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                         span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
-                            db.span_suggestion(e.span, "consider removing `.into()`", sugg);
+                            db.span_suggestion(
+                                e.span,
+                                "consider removing `.into_iter()`",
+                                sugg,
+                                Applicability::MachineApplicable, // snippet
+                            );
                         });
                     }
                 }
             },
 
-            ExprKind::Call(ref path, ref args) => if let ExprKind::Path(ref qpath) = path.node {
-                if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) {
-                    if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
-                        let a = cx.tables.expr_ty(e);
-                        let b = cx.tables.expr_ty(&args[0]);
-                        if same_tys(cx, a, b) {
-                            let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
-                            let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
-                            span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
-                                db.span_suggestion(e.span, &sugg_msg, sugg);
-                            });
+            ExprKind::Call(ref path, ref args) => {
+                if let ExprKind::Path(ref qpath) = path.node {
+                    if let Some(def_id) = resolve_node(cx, qpath, path.hir_id).opt_def_id() {
+                        if match_def_path(cx, def_id, &*paths::FROM_FROM) {
+                            let a = cx.tables.expr_ty(e);
+                            let b = cx.tables.expr_ty(&args[0]);
+                            if same_tys(cx, a, b) {
+                                let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
+                                let sugg_msg =
+                                    format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
+                                span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
+                                    db.span_suggestion(
+                                        e.span,
+                                        &sugg_msg,
+                                        sugg,
+                                        Applicability::MachineApplicable, // snippet
+                                    );
+                                });
+                            }
                         }
                     }
                 }
@@ -90,7 +118,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
     }
 
     fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if Some(&e.id) == self.try_desugar_arm.last() {
+        if Some(&e.hir_id) == self.try_desugar_arm.last() {
             self.try_desugar_arm.pop();
         }
     }
index 23b34362171986d2b6ba43e1e432e6e357546841..b3ab46781adcda3fe34bfa7353eb2f7664de5211 100644 (file)
@@ -1,40 +1,34 @@
-use crate::consts::{constant_simple, Constant};
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::codemap::Span;
-use crate::utils::{in_macro, snippet, span_lint, unsext, clip};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
+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};
 
-/// **What it does:** Checks for identity operations, e.g. `x + 0`.
-///
-/// **Why is this bad?** This code can be removed without changing the
-/// meaning. So it just obscures what's going on. Delete it mercilessly.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x / 1 + 0 * 1 - 0 | 0
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for identity operations, e.g., `x + 0`.
+    ///
+    /// **Why is this bad?** This code can be removed without changing the
+    /// meaning. So it just obscures what's going on. Delete it mercilessly.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x / 1 + 0 * 1 - 0 | 0
+    /// ```
     pub IDENTITY_OP,
     complexity,
-    "using identity operations, e.g. `x + 0` or `y / 1`"
+    "using identity operations, e.g., `x + 0` or `y / 1`"
 }
 
-#[derive(Copy, Clone)]
-pub struct IdentityOp;
-
-impl LintPass for IdentityOp {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(IDENTITY_OP)
-    }
-}
+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(e.span) {
+        if in_macro_or_desugar(e.span) {
             return;
         }
         if let ExprKind::Binary(ref cmp, ref left, ref right) = e.node {
@@ -59,12 +53,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
     }
 }
 
-#[allow(cast_possible_wrap)]
+#[allow(clippy::cast_possible_wrap)]
 fn check(cx: &LateContext<'_, '_>, e: &Expr, m: i8, span: Span, arg: Span) {
     if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) {
         let check = match cx.tables.expr_ty(e).sty {
-            ty::TyInt(ity) => unsext(cx.tcx, -1i128, ity),
-            ty::TyUint(uty) => clip(cx.tcx, !0, uty),
+            ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
+            ty::Uint(uty) => clip(cx.tcx, !0, uty),
             _ => return,
         };
         if match m {
diff --git a/clippy_lints/src/if_let_redundant_pattern_matching.rs b/clippy_lints/src/if_let_redundant_pattern_matching.rs
deleted file mode 100644 (file)
index bc97584..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
-use crate::utils::{match_qpath, paths, snippet, span_lint_and_then};
-
-/// **What it does:** Lint for redundant pattern matching over `Result` or
-/// `Option`
-///
-/// **Why is this bad?** It's more concise and clear to just use the proper
-/// utility function
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// if let Ok(_) = Ok::<i32, i32>(42) {}
-/// if let Err(_) = Err::<i32, i32>(42) {}
-/// if let None = None::<()> {}
-/// if let Some(_) = Some(42) {}
-/// ```
-///
-/// The more idiomatic use would be:
-///
-/// ```rust
-/// if Ok::<i32, i32>(42).is_ok() {}
-/// if Err::<i32, i32>(42).is_err() {}
-/// if None::<()>.is_none() {}
-/// if Some(42).is_some() {}
-/// ```
-///
-declare_clippy_lint! {
-    pub IF_LET_REDUNDANT_PATTERN_MATCHING,
-    style,
-    "use the proper utility function avoiding an `if let`"
-}
-
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(IF_LET_REDUNDANT_PATTERN_MATCHING)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if let ExprKind::Match(ref op, ref arms, MatchSource::IfLetDesugar { .. }) = expr.node {
-            if arms[0].pats.len() == 1 {
-                let good_method = match arms[0].pats[0].node {
-                    PatKind::TupleStruct(ref path, ref pats, _) if pats.len() == 1 => {
-                        if let PatKind::Wild = pats[0].node {
-                            if match_qpath(path, &paths::RESULT_OK) {
-                                "is_ok()"
-                            } else if match_qpath(path, &paths::RESULT_ERR) {
-                                "is_err()"
-                            } else if match_qpath(path, &paths::OPTION_SOME) {
-                                "is_some()"
-                            } else {
-                                return;
-                            }
-                        } else {
-                            return;
-                        }
-                    },
-
-                    PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
-
-                    _ => return,
-                };
-
-                span_lint_and_then(
-                    cx,
-                    IF_LET_REDUNDANT_PATTERN_MATCHING,
-                    arms[0].pats[0].span,
-                    &format!("redundant pattern matching, consider using `{}`", good_method),
-                    |db| {
-                        let span = expr.span.with_hi(op.span.hi());
-                        db.span_suggestion(
-                            span,
-                            "try this",
-                            format!("if {}.{}", snippet(cx, op.span, "_"), good_method),
-                        );
-                    },
-                );
-            }
-        }
-    }
-}
index fea3069f37d3a40e7a9810fcfebdfd9284c527d5..385ba9f16c89ee63d841689270434c51b717fee4 100644 (file)
@@ -1,50 +1,44 @@
 //! lint on if branches that could be swapped so no `!` operation is necessary
 //! on the condition
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::*;
 
 use crate::utils::span_help_and_lint;
 
-/// **What it does:** Checks for usage of `!` or `!=` in an if condition with an
-/// else branch.
-///
-/// **Why is this bad?** Negations reduce the readability of statements.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if !v.is_empty() {
-///     a()
-/// } else {
-///     b()
-/// }
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// if v.is_empty() {
-///     b()
-/// } else {
-///     a()
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `!` or `!=` in an if condition with an
+    /// else branch.
+    ///
+    /// **Why is this bad?** Negations reduce the readability of statements.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if !v.is_empty() {
+    ///     a()
+    /// } else {
+    ///     b()
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// if v.is_empty() {
+    ///     b()
+    /// } else {
+    ///     a()
+    /// }
+    /// ```
     pub IF_NOT_ELSE,
     pedantic,
     "`if` branches that could be swapped so no negation operation is necessary on the condition"
 }
 
-pub struct IfNotElse;
-
-impl LintPass for IfNotElse {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(IF_NOT_ELSE)
-    }
-}
+declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
 
 impl EarlyLintPass for IfNotElse {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
new file mode 100644 (file)
index 0000000..368aeb4
--- /dev/null
@@ -0,0 +1,126 @@
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, is_expn_of, snippet_opt, span_lint_and_then};
+use rustc::hir::{intravisit::FnKind, Body, ExprKind, FnDecl, HirId, MatchSource};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::source_map::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for missing return statements at the end of a block.
+    ///
+    /// **Why is this bad?** Actually omitting the return keyword is idiomatic Rust code. Programmers
+    /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss
+    /// the last returning statement because the only difference is a missing `;`. Especially in bigger
+    /// code with multiple return paths having a `return` keyword makes it easier to find the
+    /// corresponding statements.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(x: usize) {
+    ///     x
+    /// }
+    /// ```
+    /// add return
+    /// ```rust
+    /// fn foo(x: usize) {
+    ///     return x;
+    /// }
+    /// ```
+    pub IMPLICIT_RETURN,
+    restriction,
+    "use a return statement like `return expr` instead of an expression"
+}
+
+declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);
+
+impl ImplicitReturn {
+    fn lint(cx: &LateContext<'_, '_>, outer_span: syntax_pos::Span, inner_span: syntax_pos::Span, msg: &str) {
+        span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
+            if let Some(snippet) = snippet_opt(cx, inner_span) {
+                db.span_suggestion(
+                    outer_span,
+                    msg,
+                    format!("return {}", snippet),
+                    Applicability::MachineApplicable,
+                );
+            }
+        });
+    }
+
+    fn expr_match(cx: &LateContext<'_, '_>, expr: &rustc::hir::Expr) {
+        match &expr.node {
+            // loops could be using `break` instead of `return`
+            ExprKind::Block(block, ..) | ExprKind::Loop(block, ..) => {
+                if let Some(expr) = &block.expr {
+                    Self::expr_match(cx, expr);
+                }
+                // only needed in the case of `break` with `;` at the end
+                else if let Some(stmt) = block.stmts.last() {
+                    if let rustc::hir::StmtKind::Semi(expr, ..) = &stmt.node {
+                        // make sure it's a break, otherwise we want to skip
+                        if let ExprKind::Break(.., break_expr) = &expr.node {
+                            if let Some(break_expr) = break_expr {
+                                Self::lint(cx, expr.span, break_expr.span, "change `break` to `return` as shown");
+                            }
+                        }
+                    }
+                }
+            },
+            // use `return` instead of `break`
+            ExprKind::Break(.., break_expr) => {
+                if let Some(break_expr) = break_expr {
+                    Self::lint(cx, expr.span, break_expr.span, "change `break` to `return` as shown");
+                }
+            },
+            ExprKind::Match(.., arms, source) => {
+                let check_all_arms = match source {
+                    MatchSource::IfLetDesugar {
+                        contains_else_clause: has_else,
+                    } => *has_else,
+                    _ => true,
+                };
+
+                if check_all_arms {
+                    for arm in arms {
+                        Self::expr_match(cx, &arm.body);
+                    }
+                } else {
+                    Self::expr_match(cx, &arms.first().expect("if let doesn't have a single arm").body);
+                }
+            },
+            // skip if it already has a return statement
+            ExprKind::Ret(..) => (),
+            // everything else is missing `return`
+            _ => {
+                // make sure it's not just an unreachable expression
+                if is_expn_of(expr.span, *sym::unreachable).is_none() {
+                    Self::lint(cx, expr.span, expr.span, "add `return` as shown")
+                }
+            },
+        }
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        _: FnKind<'tcx>,
+        _: &'tcx FnDecl,
+        body: &'tcx Body,
+        span: Span,
+        _: HirId,
+    ) {
+        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
+        let mir = cx.tcx.optimized_mir(def_id);
+
+        // 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) {
+            Self::expr_match(cx, &body.value);
+        }
+    }
+}
index 677f59d32cc5a70170821d490d4be95f498c2707..d0a9bb729a451b7f69f19e27daa7ceb06172c362 100644 (file)
 use crate::utils::higher;
 use crate::utils::higher::Range;
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::RangeLimits;
 
-/// **What it does:** Checks for out of bounds array indexing with a constant
-/// index.
-///
-/// **Why is this bad?** This will always panic at runtime.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-/// ```rust
-/// let x = [1,2,3,4];
-///
-/// // Bad
-/// x[9];
-/// &x[2..9];
-///
-/// // Good
-/// x[0];
-/// x[3];
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for out of bounds array indexing with a constant
+    /// index.
+    ///
+    /// **Why is this bad?** This will always panic at runtime.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    /// ```no_run
+    /// # #![allow(const_err)]
+    /// let x = [1, 2, 3, 4];
+    ///
+    /// // Bad
+    /// x[9];
+    /// &x[2..9];
+    ///
+    /// // Good
+    /// x[0];
+    /// x[3];
+    /// ```
     pub OUT_OF_BOUNDS_INDEXING,
     correctness,
     "out of bounds constant indexing"
 }
 
-/// **What it does:** Checks for usage of indexing or slicing. Arrays are special cased, this lint
-/// does report on arrays if we can tell that slicing operations are in bounds and does not
-/// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
-///
-/// **Why is this bad?** Indexing and slicing can panic at runtime and there are
-/// safe alternatives.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-/// ```rust
-/// // Vector
-/// let x = vec![0; 5];
-///
-/// // Bad
-/// x[2];
-/// &x[2..100];
-/// &x[2..];
-/// &x[..100];
-///
-/// // Good
-/// x.get(2);
-/// x.get(2..100);
-/// x.get(2..);
-/// x.get(..100);
-///
-/// // Array
-/// let y = [0, 1, 2, 3];
-///
-/// // Bad
-/// &y[10..100];
-/// &y[10..];
-/// &y[..100];
-///
-/// // Good
-/// &y[2..];
-/// &y[..2];
-/// &y[0..3];
-/// y.get(10);
-/// y.get(10..100);
-/// y.get(10..);
-/// y.get(..100);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of indexing or slicing. Arrays are special cased, this lint
+    /// does report on arrays if we can tell that slicing operations are in bounds and does not
+    /// lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
+    ///
+    /// **Why is this bad?** Indexing and slicing can panic at runtime and there are
+    /// safe alternatives.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Vector
+    /// let x = vec![0; 5];
+    ///
+    /// // Bad
+    /// x[2];
+    /// &x[2..100];
+    /// &x[2..];
+    /// &x[..100];
+    ///
+    /// // Good
+    /// x.get(2);
+    /// x.get(2..100);
+    /// x.get(2..);
+    /// x.get(..100);
+    ///
+    /// // Array
+    /// let y = [0, 1, 2, 3];
+    ///
+    /// // Bad
+    /// &y[10..100];
+    /// &y[10..];
+    /// &y[..100];
+    ///
+    /// // Good
+    /// &y[2..];
+    /// &y[..2];
+    /// &y[0..3];
+    /// y.get(10);
+    /// y.get(10..100);
+    /// y.get(10..);
+    /// y.get(..100);
+    /// ```
     pub INDEXING_SLICING,
-    pedantic,
+    restriction,
     "indexing/slicing usage"
 }
 
-#[derive(Copy, Clone)]
-pub struct IndexingSlicing;
-
-impl LintPass for IndexingSlicing {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING)
-    }
-}
+declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::Index(ref array, ref index) = &expr.node {
             let ty = cx.tables.expr_ty(array);
             if let Some(range) = higher::range(cx, index) {
-                // Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..]
-                if let ty::TyArray(_, s) = ty.sty {
+                // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
+                if let ty::Array(_, s) = ty.sty {
                     let size: u128 = s.assert_usize(cx.tcx).unwrap().into();
-                    // Index is a constant range.
-                    if let Some((start, end)) = to_const_range(cx, range, size) {
-                        if start > size || end > size {
+
+                    let const_range = to_const_range(cx, range, size);
+
+                    if let (Some(start), _) = const_range {
+                        if start > size {
+                            utils::span_lint(
+                                cx,
+                                OUT_OF_BOUNDS_INDEXING,
+                                range.start.map_or(expr.span, |start| start.span),
+                                "range is out of bounds",
+                            );
+                            return;
+                        }
+                    }
+
+                    if let (_, Some(end)) = const_range {
+                        if end > size {
                             utils::span_lint(
                                 cx,
                                 OUT_OF_BOUNDS_INDEXING,
-                                expr.span,
+                                range.end.map_or(expr.span, |end| end.span),
                                 "range is out of bounds",
                             );
+                            return;
                         }
+                    }
+
+                    if let (Some(_), Some(_)) = const_range {
+                        // early return because both start and end are constants
+                        // and we have proven above that they are in bounds
                         return;
                     }
                 }
@@ -122,16 +136,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     (None, None) => return, // [..] is ok.
                 };
 
-                utils::span_help_and_lint(
-                    cx,
-                    INDEXING_SLICING,
-                    expr.span,
-                    "slicing may panic.",
-                    help_msg,
-                );
+                utils::span_help_and_lint(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg);
             } else {
-                // Catchall non-range index, i.e. [n] or [n << m]
-                if let ty::TyArray(..) = ty.sty {
+                // Catchall non-range index, i.e., [n] or [n << m]
+                if let ty::Array(..) = ty.sty {
                     // Index is a constant uint.
                     if let Some(..) = constant(cx, cx.tables, index) {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
@@ -151,34 +159,32 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-/// Returns an option containing a tuple with the start and end (exclusive) of
-/// the range.
+/// Returns a tuple of options with the start and end (exclusive) values of
+/// the range. If the start or end is not constant, None is returned.
 fn to_const_range<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     range: Range<'_>,
     array_size: u128,
-) -> Option<(u128, u128)> {
-    let s = range
-        .start
-        .map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
+) -> (Option<u128>, Option<u128>) {
+    let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
     let start = match s {
-        Some(Some(Constant::Int(x))) => x,
-        Some(_) => return None,
-        None => 0,
+        Some(Some(Constant::Int(x))) => Some(x),
+        Some(_) => None,
+        None => Some(0),
     };
 
-    let e = range
-        .end
-        .map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
+    let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
     let end = match e {
-        Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed {
-            x + 1
-        } else {
-            x
+        Some(Some(Constant::Int(x))) => {
+            if range.limits == RangeLimits::Closed {
+                Some(x + 1)
+            } else {
+                Some(x)
+            }
         },
-        Some(_) => return None,
-        None => array_size,
+        Some(_) => None,
+        None => Some(array_size),
     };
 
-    Some((start, end))
+    (start, end)
 }
index 8b8cb32deb1afedcb8aeca0e7bf4eb2831aeb24c..a977a827321d364256bb54a682ffc70a508ab0d0 100644 (file)
@@ -1,54 +1,48 @@
-use super::utils::{get_arg_name, match_var, remove_blocks, snippet, span_lint_and_sugg};
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for matches being used to destructure a single-variant enum
-/// or tuple struct where a `let` will suffice.
-///
-/// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Wrapper {
-///     Data(i32),
-/// }
-///
-/// let wrapper = Wrapper::Data(42);
-///
-/// let data = match wrapper {
-///     Wrapper::Data(i) => i,
-/// };
-/// ```
-///
-/// The correct use would be:
-/// ```rust
-/// enum Wrapper {
-///     Data(i32),
-/// }
-///
-/// let wrapper = Wrapper::Data(42);
-/// let Wrapper::Data(data) = wrapper;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches being used to destructure a single-variant enum
+    /// or tuple struct where a `let` will suffice.
+    ///
+    /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Wrapper {
+    ///     Data(i32),
+    /// }
+    ///
+    /// let wrapper = Wrapper::Data(42);
+    ///
+    /// let data = match wrapper {
+    ///     Wrapper::Data(i) => i,
+    /// };
+    /// ```
+    ///
+    /// The correct use would be:
+    /// ```rust
+    /// enum Wrapper {
+    ///     Data(i32),
+    /// }
+    ///
+    /// let wrapper = Wrapper::Data(42);
+    /// let Wrapper::Data(data) = wrapper;
+    /// ```
     pub INFALLIBLE_DESTRUCTURING_MATCH,
     style,
     "a match statement with a single infallible arm instead of a `let`"
 }
 
-#[derive(Copy, Clone, Default)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INFALLIBLE_DESTRUCTURING_MATCH)
-    }
-}
+declare_lint_pass!(InfallibleDestructingMatch => [INFALLIBLE_DESTRUCTURING_MATCH]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InfallibleDestructingMatch {
     fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
         if_chain! {
             if let Some(ref expr) = local.init;
@@ -61,6 +55,7 @@ fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
             if match_var(body, arg);
 
             then {
+                let mut applicability = Applicability::MachineApplicable;
                 span_lint_and_sugg(
                     cx,
                     INFALLIBLE_DESTRUCTURING_MATCH,
@@ -70,10 +65,11 @@ fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
                     "try this",
                     format!(
                         "let {}({}) = {};",
-                        snippet(cx, variant_name.span, ".."),
-                        snippet(cx, local.pat.span, ".."),
-                        snippet(cx, target.span, ".."),
+                        snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
+                        snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
+                        snippet_with_applicability(cx, target.span, "..", &mut applicability),
                     ),
+                    applicability,
                 );
             }
         }
index eaa93cb62f8789f0b0209fbd311a198f8fb3fd5b..6d5c1375bc4f1ec53848ef4671f6baff2e29bb70 100644 (file)
@@ -1,53 +1,52 @@
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, paths, span_lint};
-
-/// **What it does:** Checks for iteration that is guaranteed to be infinite.
-///
-/// **Why is this bad?** While there may be places where this is acceptable
-/// (e.g. in event streams), in most cases this is simply an error.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// repeat(1_u8).iter().collect::<Vec<_>>()
-/// ```
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+
+use crate::utils::sym;
+use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint};
+use lazy_static::lazy_static;
+use syntax::symbol::Symbol;
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for iteration that is guaranteed to be infinite.
+    ///
+    /// **Why is this bad?** While there may be places where this is acceptable
+    /// (e.g., in event streams), in most cases this is simply an error.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```no_run
+    /// use std::iter;
+    ///
+    /// iter::repeat(1_u8).collect::<Vec<_>>();
+    /// ```
     pub INFINITE_ITER,
     correctness,
     "infinite iteration"
 }
 
-/// **What it does:** Checks for iteration that may be infinite.
-///
-/// **Why is this bad?** While there may be places where this is acceptable
-/// (e.g. in event streams), in most cases this is simply an error.
-///
-/// **Known problems:** The code may have a condition to stop iteration, but
-/// this lint is not clever enough to analyze it.
-///
-/// **Example:**
-/// ```rust
-/// [0..].iter().zip(infinite_iter.take_while(|x| x > 5))
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for iteration that may be infinite.
+    ///
+    /// **Why is this bad?** While there may be places where this is acceptable
+    /// (e.g., in event streams), in most cases this is simply an error.
+    ///
+    /// **Known problems:** The code may have a condition to stop iteration, but
+    /// this lint is not clever enough to analyze it.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// [0..].iter().zip(infinite_iter.take_while(|x| x > 5))
+    /// ```
     pub MAYBE_INFINITE_ITER,
     pedantic,
     "possible infinite iteration"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INFINITE_ITER, MAYBE_INFINITE_ITER)
-    }
-}
+declare_lint_pass!(InfiniteIter => [INFINITE_ITER, MAYBE_INFINITE_ITER]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InfiniteIter {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         let (lint, msg) = match complete_infinite_iter(cx, expr) {
             Infinite => (INFINITE_ITER, "infinite iteration detected"),
@@ -113,32 +112,34 @@ enum Heuristic {
 
 use self::Heuristic::{All, Always, Any, First};
 
+lazy_static! {
 /// a slice of (method name, number of args, heuristic, bounds) tuples
 /// that will be used to determine whether the method in question
 /// returns an infinite or possibly infinite iterator. The finiteness
-/// is an upper bound, e.g. some methods can return a possibly
-/// infinite iterator at worst, e.g. `take_while`.
-static HEURISTICS: &[(&str, usize, Heuristic, Finiteness)] = &[
-    ("zip", 2, All, Infinite),
-    ("chain", 2, Any, Infinite),
-    ("cycle", 1, Always, Infinite),
-    ("map", 2, First, Infinite),
-    ("by_ref", 1, First, Infinite),
-    ("cloned", 1, First, Infinite),
-    ("rev", 1, First, Infinite),
-    ("inspect", 1, First, Infinite),
-    ("enumerate", 1, First, Infinite),
-    ("peekable", 2, First, Infinite),
-    ("fuse", 1, First, Infinite),
-    ("skip", 2, First, Infinite),
-    ("skip_while", 1, First, Infinite),
-    ("filter", 2, First, Infinite),
-    ("filter_map", 2, First, Infinite),
-    ("flat_map", 2, First, Infinite),
-    ("unzip", 1, First, Infinite),
-    ("take_while", 2, First, MaybeInfinite),
-    ("scan", 3, First, MaybeInfinite),
+/// is an upper bound, e.g., some methods can return a possibly
+/// infinite iterator at worst, e.g., `take_while`.
+static ref HEURISTICS: [(Symbol, usize, Heuristic, Finiteness); 19] = [
+    (*sym::zip, 2, All, Infinite),
+    (*sym::chain, 2, Any, Infinite),
+    (*sym::cycle, 1, Always, Infinite),
+    (*sym::map, 2, First, Infinite),
+    (*sym::by_ref, 1, First, Infinite),
+    (*sym::cloned, 1, First, Infinite),
+    (*sym::rev, 1, First, Infinite),
+    (*sym::inspect, 1, First, Infinite),
+    (*sym::enumerate, 1, First, Infinite),
+    (*sym::peekable, 2, First, Infinite),
+    (*sym::fuse, 1, First, Infinite),
+    (*sym::skip, 2, First, Infinite),
+    (*sym::skip_while, 1, First, Infinite),
+    (*sym::filter, 2, First, Infinite),
+    (*sym::filter_map, 2, First, Infinite),
+    (*sym::flat_map, 2, First, Infinite),
+    (*sym::unzip, 1, First, Infinite),
+    (*sym::take_while, 2, First, MaybeInfinite),
+    (*sym::scan, 3, First, MaybeInfinite),
 ];
+}
 
 fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
     match expr.node {
@@ -150,12 +151,13 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
                         First => is_infinite(cx, &args[0]),
                         Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
                         All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
-                    }).and(cap);
+                    })
+                    .and(cap);
                 }
             }
-            if method.ident.name == "flat_map" && args.len() == 2 {
+            if method.ident.name == *sym::flat_map && args.len() == 2 {
                 if let ExprKind::Closure(_, _, body_id, _, _) = args[1].node {
-                    let body = cx.tcx.hir.body(body_id);
+                    let body = cx.tcx.hir().body(body_id);
                     return is_infinite(cx, &body.value);
                 }
             }
@@ -163,46 +165,59 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
         },
         ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
         ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) => is_infinite(cx, e),
-        ExprKind::Call(ref path, _) => if let ExprKind::Path(ref qpath) = path.node {
-            match_qpath(qpath, &paths::REPEAT).into()
-        } else {
-            Finite
+        ExprKind::Call(ref path, _) => {
+            if let ExprKind::Path(ref qpath) = path.node {
+                match_qpath(qpath, &*paths::REPEAT).into()
+            } else {
+                Finite
+            }
         },
-        ExprKind::Struct(..) => higher::range(cx, expr)
-            .map_or(false, |r| r.end.is_none())
-            .into(),
+        ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
         _ => Finite,
     }
 }
 
+lazy_static! {
 /// the names and argument lengths of methods that *may* exhaust their
 /// iterators
-static POSSIBLY_COMPLETING_METHODS: &[(&str, usize)] = &[
-    ("find", 2),
-    ("rfind", 2),
-    ("position", 2),
-    ("rposition", 2),
-    ("any", 2),
-    ("all", 2),
+static ref POSSIBLY_COMPLETING_METHODS: [(Symbol, usize); 6] = [
+    (*sym::find, 2),
+    (*sym::rfind, 2),
+    (*sym::position, 2),
+    (*sym::rposition, 2),
+    (*sym::any, 2),
+    (*sym::all, 2),
 ];
 
 /// the names and argument lengths of methods that *always* exhaust
 /// their iterators
-static COMPLETING_METHODS: &[(&str, usize)] = &[
-    ("count", 1),
-    ("collect", 1),
-    ("fold", 3),
-    ("for_each", 2),
-    ("partition", 2),
-    ("max", 1),
-    ("max_by", 2),
-    ("max_by_key", 2),
-    ("min", 1),
-    ("min_by", 2),
-    ("min_by_key", 2),
-    ("sum", 1),
-    ("product", 1),
+static ref COMPLETING_METHODS: [(Symbol, usize); 12] = [
+    (*sym::count, 1),
+    (*sym::fold, 3),
+    (*sym::for_each, 2),
+    (*sym::partition, 2),
+    (*sym::max, 1),
+    (*sym::max_by, 2),
+    (*sym::max_by_key, 2),
+    (*sym::min, 1),
+    (*sym::min_by, 2),
+    (*sym::min_by_key, 2),
+    (*sym::sum, 1),
+    (*sym::product, 1),
+];
+
+/// the paths of types that are known to be infinitely allocating
+static ref INFINITE_COLLECTORS: [Vec<Symbol>; 8] = [
+    paths::BINARY_HEAP.to_vec(),
+    paths::BTREEMAP.to_vec(),
+    paths::BTREESET.to_vec(),
+    paths::HASHMAP.to_vec(),
+    paths::HASHSET.to_vec(),
+    paths::LINKED_LIST.to_vec(),
+    paths::VEC.to_vec(),
+    paths::VEC_DEQUE.to_vec(),
 ];
+}
 
 fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
     match expr.node {
@@ -217,18 +232,23 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
                     return MaybeInfinite.and(is_infinite(cx, &args[0]));
                 }
             }
-            if method.ident.name == "last" && args.len() == 1 {
-                let not_double_ended = get_trait_def_id(cx, &paths::DOUBLE_ENDED_ITERATOR)
+            if method.ident.name == *sym::last && args.len() == 1 {
+                let not_double_ended = get_trait_def_id(cx, &*paths::DOUBLE_ENDED_ITERATOR)
                     .map_or(false, |id| !implements_trait(cx, cx.tables.expr_ty(&args[0]), id, &[]));
                 if not_double_ended {
                     return is_infinite(cx, &args[0]);
                 }
+            } else if method.ident.name == *sym::collect {
+                let ty = cx.tables.expr_ty(expr);
+                if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
+                    return is_infinite(cx, &args[0]);
+                }
             }
         },
-        ExprKind::Binary(op, ref l, ref r) => if op.node.is_comparison() {
-            return is_infinite(cx, l)
-                .and(is_infinite(cx, r))
-                .and(MaybeInfinite);
+        ExprKind::Binary(op, ref l, ref r) => {
+            if op.node.is_comparison() {
+                return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite);
+            }
         }, // TODO: ExprKind::Loop + Match
         _ => (),
     }
index fc06af81574e2de5add72571d07c5498ee2efbf6..bde784f81de8d85886328100db83d5614f541d08 100644 (file)
@@ -1,61 +1,53 @@
 //! lint on inherent implementations
 
+use crate::utils::span_lint_and_then;
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use std::collections::HashMap;
-use std::default::Default;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_data_structures::fx::FxHashMap;
 use syntax_pos::Span;
 
-/// **What it does:** Checks for multiple inherent implementations of a struct
-///
-/// **Why is this bad?** Splitting the implementation of a type makes the code harder to navigate.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct X;
-/// impl X {
-///     fn one() {}
-/// }
-/// impl X {
-///     fn other() {}
-/// }
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// struct X;
-/// impl X {
-///     fn one() {}
-///     fn other() {}
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for multiple inherent implementations of a struct
+    ///
+    /// **Why is this bad?** Splitting the implementation of a type makes the code harder to navigate.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct X;
+    /// impl X {
+    ///     fn one() {}
+    /// }
+    /// impl X {
+    ///     fn other() {}
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// struct X;
+    /// impl X {
+    ///     fn one() {}
+    ///     fn other() {}
+    /// }
+    /// ```
     pub MULTIPLE_INHERENT_IMPL,
     restriction,
     "Multiple inherent impl that could be grouped"
 }
 
-pub struct Pass {
-    impls: HashMap<def_id::DefId, (Span, Generics)>,
+#[allow(clippy::module_name_repetitions)]
+#[derive(Default)]
+pub struct MultipleInherentImpl {
+    impls: FxHashMap<def_id::DefId, (Span, Generics)>,
 }
 
-impl Default for Pass {
-    fn default() -> Self {
-        Pass { impls: HashMap::new() }
-    }
-}
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MULTIPLE_INHERENT_IMPL)
-    }
-}
+impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MultipleInherentImpl {
     fn check_item(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if let ItemKind::Impl(_, _, _, ref generics, None, _, _) = item.node {
             // Remember for each inherent implementation encoutered its span and generics
@@ -77,16 +69,17 @@ fn check_crate_post(&mut self, cx: &LateContext<'a, 'tcx>, krate: &'tcx Crate) {
                 let mut impl_spans = impls
                     .iter()
                     .filter_map(|impl_def| self.impls.get(impl_def))
-                    .filter(|(_, generics)| generics.params.len() == 0)
-                    .map(|(span, _)| span);
+                    .filter_map(|(span, generics)| if generics.params.len() == 0 { Some(span) } else { None });
                 if let Some(initial_span) = impl_spans.nth(0) {
                     impl_spans.for_each(|additional_span| {
-                        cx.span_lint_note(
+                        span_lint_and_then(
+                            cx,
                             MULTIPLE_INHERENT_IMPL,
                             *additional_span,
                             "Multiple implementations of this structure",
-                            *initial_span,
-                            "First implementation here",
+                            |db| {
+                                db.span_note(*initial_span, "First implementation here");
+                            },
                         )
                     })
                 }
index 70f88a76f45042adc32371566e70f1b215f26578..0e998b44c21fdd62adf5b8eecac85a61deac545c 100644 (file)
@@ -1,42 +1,37 @@
 //! checks for `#[inline]` on trait methods without bodies
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
-use syntax::ast::{Attribute, Name};
 use crate::utils::span_lint_and_then;
 use crate::utils::sugg::DiagnosticBuilderExt;
+use crate::utils::sym;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::{Attribute, Name};
 
-/// **What it does:** Checks for `#[inline]` on trait methods without bodies
-///
-/// **Why is this bad?** Only implementations of trait methods may be inlined.
-/// The inline attribute is ignored for trait methods without bodies.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// trait Animal {
-///     #[inline]
-///     fn name(&self) -> &'static str;
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `#[inline]` on trait methods without bodies
+    ///
+    /// **Why is this bad?** Only implementations of trait methods may be inlined.
+    /// The inline attribute is ignored for trait methods without bodies.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// trait Animal {
+    ///     #[inline]
+    ///     fn name(&self) -> &'static str;
+    /// }
+    /// ```
     pub INLINE_FN_WITHOUT_BODY,
     correctness,
     "use of `#[inline]` on trait methods without bodies"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INLINE_FN_WITHOUT_BODY)
-    }
-}
+declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InlineFnWithoutBody {
     fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
         if let TraitItemKind::Method(_, TraitMethod::Required(_)) = item.node {
             check_attrs(cx, item.ident.name, &item.attrs);
@@ -46,7 +41,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem
 
 fn check_attrs(cx: &LateContext<'_, '_>, name: Name, attrs: &[Attribute]) {
     for attr in attrs {
-        if attr.name() != "inline" {
+        if !attr.check_name(*sym::inline) {
             continue;
         }
 
@@ -56,7 +51,7 @@ fn check_attrs(cx: &LateContext<'_, '_>, name: Name, attrs: &[Attribute]) {
             attr.span,
             &format!("use of `#[inline]` on trait method `{}` which has no body", name),
             |db| {
-                db.suggest_remove_item(cx, attr.span, "remove");
+                db.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
             },
         );
     }
index 9b6fc579a31ce8b1085d239ff20580711e43b358..b59179618a6d15d7554a25a46454a845205c09e8 100644 (file)
@@ -1,41 +1,36 @@
 //! lint on blocks unnecessarily using >= with a + 1 or - 1
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ast::*;
 
 use crate::utils::{snippet_opt, span_lint_and_then};
 
-/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
-///
-///
-/// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x >= y + 1
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// x > y
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
+    ///
+    ///
+    /// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x >= y + 1
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// x > y
+    /// ```
     pub INT_PLUS_ONE,
     complexity,
     "instead of using x >= y + 1, use x > y"
 }
 
-pub struct IntPlusOne;
-
-impl LintPass for IntPlusOne {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INT_PLUS_ONE)
-    }
-}
+declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]);
 
 // cases:
 // BinOpKind::Ge
@@ -53,15 +48,15 @@ enum Side {
 }
 
 impl IntPlusOne {
-    #[allow(cast_sign_loss)]
-    fn check_lit(&self, lit: &Lit, target_value: i128) -> bool {
+    #[allow(clippy::cast_sign_loss)]
+    fn check_lit(self, lit: &Lit, target_value: i128) -> bool {
         if let LitKind::Int(value, ..) = lit.node {
             return value == (target_value as u128);
         }
         false
     }
 
-    fn check_binop(&self, cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
+    fn check_binop(self, cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<String> {
         match (binop, &lhs.node, &rhs.node) {
             // case where `x - 1 >= ...` or `-1 + x >= ...`
             (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
@@ -126,7 +121,7 @@ fn check_binop(&self, cx: &EarlyContext<'_>, binop: BinOpKind, lhs: &Expr, rhs:
     }
 
     fn generate_recommendation(
-        &self,
+        self,
         cx: &EarlyContext<'_>,
         binop: BinOpKind,
         node: &Expr,
@@ -150,10 +145,21 @@ fn generate_recommendation(
         None
     }
 
-    fn emit_warning(&self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
-        span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| {
-            db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation);
-        });
+    fn emit_warning(self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
+        span_lint_and_then(
+            cx,
+            INT_PLUS_ONE,
+            block.span,
+            "Unnecessary `>= y + 1` or `x - 1 >=`",
+            |db| {
+                db.span_suggestion(
+                    block.span,
+                    "change `>= y + 1` to `> y` as shown",
+                    recommendation,
+                    Applicability::MachineApplicable, // snippet
+                );
+            },
+        );
     }
 }
 
index b529cb3ac3813f231c7c18272d93db90621d75f0..9641e9f9e4bc21a6df940ffc869959485d93510d 100644 (file)
@@ -1,21 +1,21 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{match_def_path, paths, span_help_and_lint};
 use if_chain::if_chain;
-use rustc::ty;
 use rustc::hir::*;
-use crate::utils::{match_def_path, opt_def_id, paths, span_help_and_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty;
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
-///
-/// **Why is this bad?** Creation of null references is undefined behavior.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let bad_ref: &usize = std::mem::zeroed();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
+    ///
+    /// **Why is this bad?** Creation of null references is undefined behavior.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```no_run
+    /// let bad_ref: &usize = unsafe { std::mem::zeroed() };
+    /// ```
     pub INVALID_REF,
     correctness,
     "creation of invalid reference"
 const HELP: &str = "Creation of a null reference is undefined behavior; \
                     see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
 
-pub struct InvalidRef;
-
-impl LintPass for InvalidRef {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INVALID_REF)
-    }
-}
+declare_lint_pass!(InvalidRef => [INVALID_REF]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
@@ -40,15 +34,15 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             if let ExprKind::Call(ref path, ref args) = expr.node;
             if let ExprKind::Path(ref qpath) = path.node;
             if args.len() == 0;
-            if let ty::TyRef(..) = cx.tables.expr_ty(expr).sty;
-            if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id));
+            if let ty::Ref(..) = cx.tables.expr_ty(expr).sty;
+            if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
             then {
-                let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) |
-                             match_def_path(cx.tcx, def_id, &paths::INIT)
+                let msg = if match_def_path(cx, def_id, &*paths::MEM_ZEROED) |
+                             match_def_path(cx, def_id, &*paths::INIT)
                 {
                     ZERO_REF_SUMMARY
-                } else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) |
-                          match_def_path(cx.tcx, def_id, &paths::UNINIT)
+                } else if match_def_path(cx, def_id, &*paths::MEM_UNINIT) |
+                          match_def_path(cx, def_id, &*paths::UNINIT)
                 {
                     UNINIT_REF_SUMMARY
                 } else {
index 07ef086d694c77603c4af9dfccc817216bf96ee1..226809a2e28b3f6b151a247e84c408f537a8f345 100644 (file)
@@ -1,55 +1,50 @@
 //! lint when items are used after statements
 
+use crate::utils::{in_macro_or_desugar, span_lint};
 use matches::matches;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::*;
-use crate::utils::{in_macro, span_lint};
 
-/// **What it does:** Checks for items declared after some statement in a block.
-///
-/// **Why is this bad?** Items live for the entire scope they are declared
-/// in. But statements are processed in order. This might cause confusion as
-/// it's hard to figure out which item is meant in a statement.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn foo() {
-///     println!("cake");
-/// }
-///
-/// fn main() {
-///     foo(); // prints "foo"
-///     fn foo() {
-///         println!("foo");
-///     }
-///     foo(); // prints "foo"
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for items declared after some statement in a block.
+    ///
+    /// **Why is this bad?** Items live for the entire scope they are declared
+    /// in. But statements are processed in order. This might cause confusion as
+    /// it's hard to figure out which item is meant in a statement.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo() {
+    ///     println!("cake");
+    /// }
+    ///
+    /// fn main() {
+    ///     foo(); // prints "foo"
+    ///     fn foo() {
+    ///         println!("foo");
+    ///     }
+    ///     foo(); // prints "foo"
+    /// }
+    /// ```
     pub ITEMS_AFTER_STATEMENTS,
     pedantic,
     "blocks where an item comes after a statement"
 }
 
-pub struct ItemsAfterStatements;
-
-impl LintPass for ItemsAfterStatements {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ITEMS_AFTER_STATEMENTS)
-    }
-}
+declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
 
 impl EarlyLintPass for ItemsAfterStatements {
     fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
-        if in_macro(item.span) {
+        if in_macro_or_desugar(item.span) {
             return;
         }
 
         // skip initial items
-        let stmts = item.stmts
+        let stmts = item
+            .stmts
             .iter()
             .map(|stmt| &stmt.node)
             .skip_while(|s| matches!(**s, StmtKind::Item(..)));
@@ -57,7 +52,7 @@ fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
         // lint on all further items
         for stmt in stmts {
             if let StmtKind::Item(ref it) = *stmt {
-                if in_macro(it.span) {
+                if in_macro_or_desugar(it.span) {
                     return;
                 }
                 if let ItemKind::MacroDef(..) = it.node {
index 2c03b6b5f682c2ed766d65d849aa2e52bc44f85d..e447be82b03dfdb760abf8c72e0584dcb2f0e679 100644 (file)
@@ -1,28 +1,29 @@
 //! lint when there is a large size difference between variants on an enum
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
 use crate::utils::{snippet_opt, span_lint_and_then};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty::layout::LayoutOf;
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for large size differences between variants on
-/// `enum`s.
-///
-/// **Why is this bad?** Enum size is bounded by the largest variant. Having a
-/// large variant
-/// can penalize the memory layout of that enum.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Test {
-///    A(i32),
-///    B([i32; 8000]),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for large size differences between variants on
+    /// `enum`s.
+    ///
+    /// **Why is this bad?** Enum size is bounded by the largest variant. Having a
+    /// large variant
+    /// can penalize the memory layout of that enum.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Test {
+    ///     A(i32),
+    ///     B([i32; 8000]),
+    /// }
+    /// ```
     pub LARGE_ENUM_VARIANT,
     perf,
     "large size difference between variants on an enum"
@@ -41,19 +42,14 @@ pub fn new(maximum_size_difference_allowed: u64) -> Self {
     }
 }
 
-impl LintPass for LargeEnumVariant {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(LARGE_ENUM_VARIANT)
-    }
-}
+impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item) {
-        let did = cx.tcx.hir.local_def_id(item.id);
+        let did = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
         if let ItemKind::Enum(ref def, _) = item.node {
             let ty = cx.tcx.type_of(did);
-            let adt = ty.ty_adt_def()
-                .expect("already checked whether this is an enum");
+            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
 
             let mut smallest_variant: Option<(_, _)> = None;
             let mut largest_variant: Option<(_, _)> = None;
@@ -90,10 +86,10 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item) {
                         |db| {
                             if variant.fields.len() == 1 {
                                 let span = match def.variants[i].node.data {
-                                    VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => {
+                                    VariantData::Struct(ref fields, ..) | VariantData::Tuple(ref fields, ..) => {
                                         fields[0].ty.span
                                     },
-                                    VariantData::Unit(_) => unreachable!(),
+                                    VariantData::Unit(..) => unreachable!(),
                                 };
                                 if let Some(snip) = snippet_opt(cx, span) {
                                     db.span_suggestion(
@@ -101,6 +97,7 @@ fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item) {
                                         "consider boxing the large fields to reduce the total size of the \
                                          enum",
                                         format!("Box<{}>", snip),
+                                        Applicability::MaybeIncorrect,
                                     );
                                     return;
                                 }
index b73f912fad5ec69e56c1f5f13aca018876e53116..131f0301c424ff1f6d5c8b1f477556f2caad33f2 100644 (file)
@@ -1,70 +1,83 @@
+use crate::utils::sym;
+use crate::utils::{
+    get_item_name, in_macro_or_desugar, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty,
+};
 use rustc::hir::def_id::DefId;
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use std::collections::HashSet;
-use syntax::ast::{Lit, LitKind, Name};
-use syntax::codemap::{Span, Spanned};
-use crate::utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use syntax::ast::{LitKind, Name};
+use syntax::source_map::{Span, Spanned};
+use syntax::symbol::Symbol;
 
-/// **What it does:** Checks for getting the length of something via `.len()`
-/// just to compare to zero, and suggests using `.is_empty()` where applicable.
-///
-/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
-/// than calculating their length. Notably, for slices, getting the length
-/// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
-/// good to get into the habit of using `.is_empty()`, and having it is cheap.
-/// Besides, it makes the intent clearer than a manual comparison.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if x.len() == 0 { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for getting the length of something via `.len()`
+    /// just to compare to zero, and suggests using `.is_empty()` where applicable.
+    ///
+    /// **Why is this bad?** Some structures can answer `.is_empty()` much faster
+    /// than calculating their length. Notably, for slices, getting the length
+    /// requires a subtraction whereas `.is_empty()` is just a comparison. So it is
+    /// good to get into the habit of using `.is_empty()`, and having it is cheap.
+    /// Besides, it makes the intent clearer than a manual comparison.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if x.len() == 0 {
+    ///     ..
+    /// }
+    /// if y.len() != 0 {
+    ///     ..
+    /// }
+    /// ```
+    /// instead use
+    /// ```ignore
+    /// if x.is_empty() {
+    ///     ..
+    /// }
+    /// if !y.is_empty() {
+    ///     ..
+    /// }
+    /// ```
     pub LEN_ZERO,
     style,
-    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
-     could be used instead"
+    "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead"
 }
 
-/// **What it does:** Checks for items that implement `.len()` but not
-/// `.is_empty()`.
-///
-/// **Why is this bad?** It is good custom to have both methods, because for
-/// some data structures, asking about the length will be a costly operation,
-/// whereas `.is_empty()` can usually answer in constant time. Also it used to
-/// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
-/// lint will ignore such entities.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// impl X {
-///     pub fn len(&self) -> usize { .. }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for items that implement `.len()` but not
+    /// `.is_empty()`.
+    ///
+    /// **Why is this bad?** It is good custom to have both methods, because for
+    /// some data structures, asking about the length will be a costly operation,
+    /// whereas `.is_empty()` can usually answer in constant time. Also it used to
+    /// lead to false positives on the [`len_zero`](#len_zero) lint – currently that
+    /// lint will ignore such entities.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// impl X {
+    ///     pub fn len(&self) -> usize {
+    ///         ..
+    ///     }
+    /// }
+    /// ```
     pub LEN_WITHOUT_IS_EMPTY,
     style,
     "traits or impls with a public `len` method but no corresponding `is_empty` method"
 }
 
-#[derive(Copy, Clone)]
-pub struct LenZero;
-
-impl LintPass for LenZero {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(LEN_ZERO, LEN_WITHOUT_IS_EMPTY)
-    }
-}
+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(item.span) {
+        if in_macro_or_desugar(item.span) {
             return;
         }
 
@@ -76,7 +89,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if in_macro(expr.span) {
+        if in_macro_or_desugar(expr.span) {
             return;
         }
 
@@ -98,8 +111,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     check_cmp(cx, expr.span, left, right, "", 1); // len < 1
                     check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len
                 },
-                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len <= 1
-                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 >= len
+                BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1
+                BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len
                 _ => (),
             }
         }
@@ -107,36 +120,40 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
 }
 
 fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
-    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
-        item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
-            has_self && {
-                let did = cx.tcx.hir.local_def_id(item.id.node_id);
-                cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
+    fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: Symbol) -> bool {
+        item.ident.name == name
+            && if let AssociatedItemKind::Method { has_self } = item.kind {
+                has_self && {
+                    let did = cx.tcx.hir().local_def_id_from_hir_id(item.id.hir_id);
+                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
+                }
+            } else {
+                false
             }
-        } else {
-            false
-        }
     }
 
     // fill the set with current and super traits
-    fn fill_trait_set(traitt: DefId, set: &mut HashSet<DefId>, cx: &LateContext<'_, '_>) {
+    fn fill_trait_set(traitt: DefId, set: &mut FxHashSet<DefId>, cx: &LateContext<'_, '_>) {
         if set.insert(traitt) {
-            for supertrait in ::rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
+            for supertrait in rustc::traits::supertrait_def_ids(cx.tcx, traitt) {
                 fill_trait_set(supertrait, set, cx);
             }
         }
     }
 
-    if cx.access_levels.is_exported(visited_trait.id) && trait_items.iter().any(|i| is_named_self(cx, i, "len")) {
-        let mut current_and_super_traits = HashSet::new();
-        let visited_trait_def_id = cx.tcx.hir.local_def_id(visited_trait.id);
+    if cx.access_levels.is_exported(visited_trait.hir_id) && trait_items.iter().any(|i| is_named_self(cx, i, *sym::len))
+    {
+        let mut current_and_super_traits = FxHashSet::default();
+        let visited_trait_def_id = cx.tcx.hir().local_def_id_from_hir_id(visited_trait.hir_id);
         fill_trait_set(visited_trait_def_id, &mut current_and_super_traits, cx);
 
         let is_empty_method_found = current_and_super_traits
             .iter()
             .flat_map(|&i| cx.tcx.associated_items(i))
             .any(|i| {
-                i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.ident.name == "is_empty"
+                i.kind == ty::AssociatedKind::Method
+                    && i.method_has_self_argument
+                    && i.ident.name == *sym::is_empty
                     && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
             });
 
@@ -147,7 +164,7 @@ fn fill_trait_set(traitt: DefId, set: &mut HashSet<DefId>, cx: &LateContext<'_,
                 visited_trait.span,
                 &format!(
                     "trait `{}` has a `len` method but no (possibly inherited) `is_empty` method",
-                    visited_trait.name
+                    visited_trait.ident.name
                 ),
             );
         }
@@ -155,19 +172,20 @@ fn fill_trait_set(traitt: DefId, set: &mut HashSet<DefId>, cx: &LateContext<'_,
 }
 
 fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
-    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
-        item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
-            has_self && {
-                let did = cx.tcx.hir.local_def_id(item.id.node_id);
-                cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
+    fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: Symbol) -> bool {
+        item.ident.name == name
+            && if let AssociatedItemKind::Method { has_self } = item.kind {
+                has_self && {
+                    let did = cx.tcx.hir().local_def_id_from_hir_id(item.id.hir_id);
+                    cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
+                }
+            } else {
+                false
             }
-        } else {
-            false
-        }
     }
 
-    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
-        if cx.access_levels.is_exported(is_empty.id.node_id) {
+    let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, *sym::is_empty)) {
+        if cx.access_levels.is_exported(is_empty.id.hir_id) {
             return;
         } else {
             "a private"
@@ -176,9 +194,9 @@ fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bo
         "no corresponding"
     };
 
-    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, "len")) {
-        if cx.access_levels.is_exported(i.id.node_id) {
-            let def_id = cx.tcx.hir.local_def_id(item.id);
+    if let Some(i) = impl_items.iter().find(|i| is_named_self(cx, i, *sym::len)) {
+        if cx.access_levels.is_exported(i.id.hir_id) {
+            let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
             let ty = cx.tcx.type_of(def_id);
 
             span_lint(
@@ -198,45 +216,55 @@ fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op
     if let (&ExprKind::MethodCall(ref method_path, _, ref args), &ExprKind::Lit(ref lit)) = (&method.node, &lit.node) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
-            if name == "is_empty" {
+            if name == *sym::is_empty {
                 return;
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, lit, op, compare_to)
+        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
     }
 }
 
-fn check_len(cx: &LateContext<'_, '_>, span: Span, method_name: Name, args: &[Expr], lit: &Lit, op: &str, compare_to: u32) {
-    if let Spanned {
-        node: LitKind::Int(lit, _),
-        ..
-    } = *lit
-    {
+fn check_len(
+    cx: &LateContext<'_, '_>,
+    span: Span,
+    method_name: Name,
+    args: &[Expr],
+    lit: &LitKind,
+    op: &str,
+    compare_to: u32,
+) {
+    if let LitKind::Int(lit, _) = *lit {
         // check if length is compared to the specified number
         if lit != u128::from(compare_to) {
             return;
         }
 
-        if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
+        if method_name == *sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
+            let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
                 LEN_ZERO,
                 span,
                 &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
-                "using `is_empty` is more concise",
-                format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")),
+                "using `is_empty` is clearer and more explicit",
+                format!(
+                    "{}{}.is_empty()",
+                    op,
+                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
+                ),
+                applicability,
             );
         }
     }
 }
 
-/// Check if this type has an `is_empty` method.
+/// Checks if this type has an `is_empty` method.
 fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
-    /// Get an `AssociatedItem` and return true if it matches `is_empty(self)`.
+    /// Gets an `AssociatedItem` and return true if it matches `is_empty(self)`.
     fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
         if let ty::AssociatedKind::Method = item.kind {
-            if item.ident.name == "is_empty" {
+            if item.ident.name == *sym::is_empty {
                 let sig = cx.tcx.fn_sig(item.def_id);
                 let ty = sig.skip_binder();
                 ty.inputs().len() == 1
@@ -248,23 +276,28 @@ fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssociatedItem) -> bool {
         }
     }
 
-    /// Check the inherent impl's items for an `is_empty(self)` method.
+    /// Checks the inherent impl's items for an `is_empty(self)` method.
     fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
-        cx.tcx.inherent_impls(id).iter().any(|imp| {
-            cx.tcx
-                .associated_items(*imp)
-                .any(|item| is_is_empty(cx, &item))
-        })
+        cx.tcx
+            .inherent_impls(id)
+            .iter()
+            .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
     }
 
     let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
     match ty.sty {
-        ty::TyDynamic(ref tt, ..) => cx.tcx
-            .associated_items(tt.principal().expect("trait impl not found").def_id())
-            .any(|item| is_is_empty(cx, &item)),
-        ty::TyProjection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
-        ty::TyAdt(id, _) => has_is_empty_impl(cx, id.did),
-        ty::TyArray(..) | ty::TySlice(..) | ty::TyStr => true,
+        ty::Dynamic(ref tt, ..) => {
+            if let Some(principal) = tt.principal() {
+                cx.tcx
+                    .associated_items(principal.def_id())
+                    .any(|item| is_is_empty(cx, &item))
+            } else {
+                false
+            }
+        },
+        ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
+        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
+        ty::Array(..) | ty::Slice(..) | ty::Str => true,
         _ => false,
     }
 }
index 57ca5eff95530b8646dc5dd14ac2f0214c9376e4..990d8facd13473137606b8858aedad4b1a31cbb4 100644 (file)
@@ -1,65 +1,58 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{higher, snippet, span_lint_and_then};
 use if_chain::if_chain;
 use rustc::hir;
+use rustc::hir::def::Res;
 use rustc::hir::BindingAnnotation;
-use rustc::hir::def::Def;
-use syntax::ast;
-use crate::utils::{snippet, span_lint_and_then};
-
-/// **What it does:** Checks for variable declarations immediately followed by a
-/// conditional affectation.
-///
-/// **Why is this bad?** This is not idiomatic Rust.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// let foo;
-///
-/// if bar() {
-///     foo = 42;
-/// } else {
-///     foo = 0;
-/// }
-///
-/// let mut baz = None;
-///
-/// if bar() {
-///     baz = Some(42);
-/// }
-/// ```
-///
-/// should be written
-///
-/// ```rust,ignore
-/// let foo = if bar() {
-///     42
-/// } else {
-///     0
-/// };
-///
-/// let baz = if bar() {
-///     Some(42)
-/// } else {
-///     None
-/// };
-/// ```
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for variable declarations immediately followed by a
+    /// conditional affectation.
+    ///
+    /// **Why is this bad?** This is not idiomatic Rust.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// let foo;
+    ///
+    /// if bar() {
+    ///     foo = 42;
+    /// } else {
+    ///     foo = 0;
+    /// }
+    ///
+    /// let mut baz = None;
+    ///
+    /// if bar() {
+    ///     baz = Some(42);
+    /// }
+    /// ```
+    ///
+    /// should be written
+    ///
+    /// ```rust,ignore
+    /// let foo = if bar() {
+    ///     42
+    /// } else {
+    ///     0
+    /// };
+    ///
+    /// let baz = if bar() {
+    ///     Some(42)
+    /// } else {
+    ///     None
+    /// };
+    /// ```
     pub USELESS_LET_IF_SEQ,
     style,
     "unidiomatic `let mut` declaration followed by initialization in `if`"
 }
 
-#[derive(Copy, Clone)]
-pub struct LetIfSeq;
-
-impl LintPass for LetIfSeq {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(USELESS_LET_IF_SEQ)
-    }
-}
+declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetIfSeq {
     fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
@@ -67,11 +60,10 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
         while let Some(stmt) = it.next() {
             if_chain! {
                 if let Some(expr) = it.peek();
-                if let hir::StmtKind::Decl(ref decl, _) = stmt.node;
-                if let hir::DeclKind::Local(ref decl) = decl.node;
-                if let hir::PatKind::Binding(mode, canonical_id, ident, None) = decl.pat.node;
-                if let hir::StmtKind::Expr(ref if_, _) = expr.node;
-                if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.node;
+                if let hir::StmtKind::Local(ref local) = stmt.node;
+                if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.node;
+                if let hir::StmtKind::Expr(ref if_) = expr.node;
+                if let Some((ref cond, ref then, ref else_)) = higher::if_block(&if_);
                 if !used_in_expr(cx, canonical_id, cond);
                 if let hir::ExprKind::Block(ref then, _) = then.node;
                 if let Some(value) = check_assign(cx, canonical_id, &*then);
@@ -79,11 +71,18 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
                 then {
                     let span = stmt.span.to(if_.span);
 
+                    let has_interior_mutability = !cx.tables.node_type(canonical_id).is_freeze(
+                        cx.tcx,
+                        cx.param_env,
+                        span
+                    );
+                    if has_interior_mutability { return; }
+
                     let (default_multi_stmts, default) = if let Some(ref else_) = *else_ {
                         if let hir::ExprKind::Block(ref else_, _) = else_.node {
                             if let Some(default) = check_assign(cx, canonical_id, else_) {
                                 (else_.stmts.len() > 1, default)
-                            } else if let Some(ref default) = decl.init {
+                            } else if let Some(ref default) = local.init {
                                 (true, &**default)
                             } else {
                                 continue;
@@ -91,7 +90,7 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
                         } else {
                             continue;
                         }
-                    } else if let Some(ref default) = decl.init {
+                    } else if let Some(ref default) = local.init {
                         (false, &**default)
                     } else {
                         continue;
@@ -120,9 +119,12 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
                                        span,
                                        "`if _ { .. } else { .. }` is an expression",
                                        |db| {
-                                           db.span_suggestion(span,
-                                                              "it is more idiomatic to write",
-                                                              sug);
+                                           db.span_suggestion(
+                                                span,
+                                                "it is more idiomatic to write",
+                                                sug,
+                                                Applicability::HasPlaceholders,
+                                            );
                                            if !mutability.is_empty() {
                                                db.note("you might not need `mut` at all");
                                            }
@@ -135,7 +137,7 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
 
 struct UsedVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    id: ast::NodeId,
+    id: hir::HirId,
     used: bool,
 }
 
@@ -143,7 +145,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         if_chain! {
             if let hir::ExprKind::Path(ref qpath) = expr.node;
-            if let Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
+            if let Res::Local(local_id) = self.cx.tables.qpath_res(qpath, expr.hir_id);
             if self.id == local_id;
             then {
                 self.used = true;
@@ -159,16 +161,16 @@ fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap
 
 fn check_assign<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
-    decl: ast::NodeId,
+    decl: hir::HirId,
     block: &'tcx hir::Block,
 ) -> Option<&'tcx hir::Expr> {
     if_chain! {
         if block.expr.is_none();
         if let Some(expr) = block.stmts.iter().last();
-        if let hir::StmtKind::Semi(ref expr, _) = expr.node;
+        if let hir::StmtKind::Semi(ref expr) = expr.node;
         if let hir::ExprKind::Assign(ref var, ref value) = expr.node;
         if let hir::ExprKind::Path(ref qpath) = var.node;
-        if let Def::Local(local_id) = cx.tables.qpath_def(qpath, var.hir_id);
+        if let Res::Local(local_id) = cx.tables.qpath_res(qpath, var.hir_id);
         if decl == local_id;
         then {
             let mut v = UsedVisitor {
@@ -192,12 +194,8 @@ fn check_assign<'a, 'tcx>(
     None
 }
 
-fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: ast::NodeId, expr: &'tcx hir::Expr) -> bool {
-    let mut v = UsedVisitor {
-        cx,
-        id,
-        used: false,
-    };
+fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: hir::HirId, expr: &'tcx hir::Expr) -> bool {
+    let mut v = UsedVisitor { cx, id, used: false };
     hir::intravisit::walk_expr(&mut v, expr);
     v.used
 }
index 4a23de3b8fd234a863d44ab740e11875ea5d1313..400abb5a498065e957e0366dad8342f07dd3df73 100644 (file)
 // error-pattern:cargo-clippy
 
 #![feature(box_syntax)]
+#![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(stmt_expr_attributes)]
-#![feature(range_contains)]
-#![feature(macro_vis_matcher)]
-#![allow(unknown_lints, shadow_reuse, missing_docs_in_private_items)]
-#![recursion_limit = "256"]
-#![allow(stable_features)]
-#![feature(iterator_find_map)]
-#![feature(macro_at_most_once_rep)]
-#![feature(rust_2018_preview)]
-#![warn(rust_2018_idioms)]
+#![allow(clippy::missing_docs_in_private_items)]
+#![recursion_limit = "512"]
+#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
+#![deny(internal)]
+#![feature(crate_visibility_modifier)]
+#![feature(concat_idents)]
 
-use toml;
-use rustc_plugin;
-use rustc;
+// FIXME: switch to something more ergonomic here, once available.
+// (Currently there is no way to opt into sysroot crates without `extern crate`.)
+#[allow(unused_extern_crates)]
+extern crate fmt_macros;
+#[allow(unused_extern_crates)]
+extern crate rustc;
+#[allow(unused_extern_crates)]
+extern crate rustc_data_structures;
+#[allow(unused_extern_crates)]
+extern crate rustc_errors;
+#[allow(unused_extern_crates)]
+extern crate rustc_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;
+#[allow(unused_extern_crates)]
+extern crate syntax;
+#[allow(unused_extern_crates)]
+extern crate syntax_pos;
 
+use toml;
 
+/// Macro used to declare a Clippy lint.
+///
+/// Every lint declaration consists of 4 parts:
+///
+/// 1. The documentation, which is used for the website
+/// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions.
+/// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or
+///    `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of.
+/// 4. The `description` that contains a short explanation on what's wrong with code where the
+///    lint is triggered.
+///
+/// Currently the categories `style`, `correctness`, `complexity` and `perf` are enabled by default.
+/// As said in the README.md of this repository, if the lint level mapping changes, please update
+/// README.md.
+///
+/// # Example
+///
+/// ```
+/// # #![feature(rustc_private)]
+/// # #[allow(unused_extern_crates)]
+/// # extern crate rustc;
+/// # #[macro_use]
+/// # use clippy_lints::declare_clippy_lint;
+/// use rustc::declare_tool_lint;
+///
+/// declare_clippy_lint! {
+///     /// **What it does:** Checks for ... (describe what the lint matches).
+///     ///
+///     /// **Why is this bad?** Supply the reason for linting the code.
+///     ///
+///     /// **Known problems:** None. (Or describe where it could go wrong.)
+///     ///
+///     /// **Example:**
+///     ///
+///     /// ```rust
+///     /// // Bad
+///     /// Insert a short example of code that triggers the lint
+///     ///
+///     /// // Good
+///     /// Insert a short example of improved code that doesn't trigger the lint
+///     /// ```
+///     pub LINT_NAME,
+///     pedantic,
+///     "description"
+/// }
+/// ```
+/// [lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+#[macro_export]
 macro_rules! declare_clippy_lint {
-    { pub $name:tt, style, $description:tt } => {
-        declare_lint! { pub $name, Warn, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, style, $description:tt } => {
+        declare_tool_lint! {
+            $(#[$attr])* pub clippy::$name, Warn, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, correctness, $description:tt } => {
-        declare_lint! { pub $name, Deny, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, correctness, $description:tt } => {
+        declare_tool_lint! {
+            $(#[$attr])* pub clippy::$name, Deny, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, complexity, $description:tt } => {
-        declare_lint! { pub $name, Warn, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, complexity, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Warn, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, perf, $description:tt } => {
-        declare_lint! { pub $name, Warn, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, perf, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Warn, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, pedantic, $description:tt } => {
-        declare_lint! { pub $name, Allow, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, pedantic, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Allow, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, restriction, $description:tt } => {
-        declare_lint! { pub $name, Allow, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, restriction, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Allow, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, cargo, $description:tt } => {
-        declare_lint! { pub $name, Allow, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, cargo, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Allow, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, nursery, $description:tt } => {
-        declare_lint! { pub $name, Allow, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, nursery, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Allow, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, internal, $description:tt } => {
-        declare_lint! { pub $name, Allow, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, internal, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Allow, $description, report_in_external_macro: true
+        }
     };
-    { pub $name:tt, internal_warn, $description:tt } => {
-        declare_lint! { pub $name, Warn, $description, report_in_external_macro: true }
+    { $(#[$attr:meta])* pub $name:tt, internal_warn, $description:tt } => {
+        declare_tool_lint! {
+            pub clippy::$name, Warn, $description, report_in_external_macro: true
+        }
     };
 }
 
-pub mod consts;
+mod consts;
 #[macro_use]
-pub mod utils;
+mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 pub mod approx_const;
 pub mod arithmetic;
+pub mod assertions_on_constants;
 pub mod assign_ops;
 pub mod attrs;
 pub mod bit_mask;
@@ -66,15 +153,19 @@ macro_rules! declare_clippy_lint {
 pub mod block_in_if_condition;
 pub mod booleans;
 pub mod bytecount;
+pub mod cargo_common_metadata;
+pub mod cognitive_complexity;
 pub mod collapsible_if;
 pub mod const_static_lifetime;
 pub mod copies;
-pub mod cyclomatic_complexity;
+pub mod copy_iterator;
+pub mod dbg_macro;
 pub mod default_trait_access;
 pub mod derive;
 pub mod doc;
 pub mod double_comparison;
 pub mod double_parens;
+pub mod drop_bounds;
 pub mod drop_forget_ref;
 pub mod duration_subsec;
 pub mod else_if_without_else;
@@ -96,8 +187,8 @@ macro_rules! declare_clippy_lint {
 pub mod functions;
 pub mod identity_conversion;
 pub mod identity_op;
-pub mod if_let_redundant_pattern_matching;
 pub mod if_not_else;
+pub mod implicit_return;
 pub mod indexing_slicing;
 pub mod infallible_destructuring_match;
 pub mod infinite_iter;
@@ -115,11 +206,14 @@ macro_rules! declare_clippy_lint {
 pub mod map_clone;
 pub mod map_unit_fn;
 pub mod matches;
+pub mod mem_discriminant;
 pub mod mem_forget;
+pub mod mem_replace;
 pub mod methods;
 pub mod minmax;
 pub mod misc;
 pub mod misc_early;
+pub mod missing_const_for_fn;
 pub mod missing_doc;
 pub mod missing_inline;
 pub mod multiple_crate_versions;
@@ -143,22 +237,28 @@ macro_rules! declare_clippy_lint {
 pub mod overflow_check_conditional;
 pub mod panic_unimplemented;
 pub mod partialeq_ne_impl;
+pub mod path_buf_push_overwrite;
 pub mod precedence;
 pub mod ptr;
+pub mod ptr_offset_with_cast;
 pub mod question_mark;
 pub mod ranges;
+pub mod redundant_clone;
 pub mod redundant_field_names;
+pub mod redundant_pattern_matching;
 pub mod reference;
 pub mod regex;
 pub mod replace_consts;
 pub mod returns;
 pub mod serde_api;
 pub mod shadow;
+pub mod slow_vector_initialization;
 pub mod strings;
 pub mod suspicious_trait_impl;
 pub mod swap;
 pub mod temporary_assignment;
 pub mod transmute;
+pub mod transmuting_null;
 pub mod trivially_copy_pass_by_ref;
 pub mod types;
 pub mod unicode;
@@ -168,21 +268,52 @@ macro_rules! declare_clippy_lint {
 pub mod unwrap;
 pub mod use_self;
 pub mod vec;
+pub mod wildcard_dependencies;
 pub mod write;
 pub mod zero_div_zero;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
+pub use crate::utils::conf::Conf;
+
 mod reexport {
-    crate use syntax::ast::{Name, NodeId};
+    crate use syntax::ast::Name;
 }
 
-pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore) {
-    store.register_pre_expansion_pass(Some(session), box write::Pass);
+/// Register all pre expansion lints
+///
+/// Pre-expansion lints run before any macro expansion has happened.
+///
+/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
+/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
+///
+/// Used in `./src/driver.rs`.
+pub fn register_pre_expansion_lints(
+    session: &rustc::session::Session,
+    store: &mut rustc::lint::LintStore,
+    conf: &Conf,
+) {
+    store.register_pre_expansion_pass(Some(session), true, false, box write::Write);
+    store.register_pre_expansion_pass(
+        Some(session),
+        true,
+        false,
+        box redundant_field_names::RedundantFieldNames,
+    );
+    store.register_pre_expansion_pass(
+        Some(session),
+        true,
+        false,
+        box non_expressive_names::NonExpressiveNames {
+            single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
+        },
+    );
+    store.register_pre_expansion_pass(Some(session), true, false, box attrs::DeprecatedCfgAttribute);
+    store.register_pre_expansion_pass(Some(session), true, false, box dbg_macro::DbgMacro);
 }
 
-#[cfg_attr(rustfmt, rustfmt_skip)]
-pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
-    let conf = match utils::conf::file_from_args(reg.args()) {
+#[doc(hidden)]
+pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf {
+    match utils::conf::file_from_args(reg.args()) {
         Ok(file_name) => {
             // if the user specified a file, it must exist, otherwise default to `clippy.toml` but
             // do not require the file to exist
@@ -192,41 +323,60 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
                 match utils::conf::lookup_conf_file() {
                     Ok(path) => path,
                     Err(error) => {
-                        reg.sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)).emit();
+                        reg.sess
+                            .struct_err(&format!("error finding Clippy's configuration file: {}", error))
+                            .emit();
                         None
-                    }
+                    },
                 }
             };
 
-            let file_name = file_name.map(|file_name| if file_name.is_relative() {
-                reg.sess
-                    .local_crate_source_file
-                    .as_ref()
-                    .and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf))
-                    .unwrap_or_default()
-                    .join(file_name)
-            } else {
-                file_name
+            let file_name = file_name.map(|file_name| {
+                if file_name.is_relative() {
+                    reg.sess
+                        .local_crate_source_file
+                        .as_ref()
+                        .and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf))
+                        .unwrap_or_default()
+                        .join(file_name)
+                } else {
+                    file_name
+                }
             });
 
-            let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref()));
+            let (conf, errors) = utils::conf::read(file_name.as_ref().map(std::convert::AsRef::as_ref));
 
             // all conf errors are non-fatal, we just use the default conf in case of error
             for error in errors {
-                reg.sess.struct_err(&format!("error reading Clippy's configuration file `{}`: {}", file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""), error)).emit();
+                reg.sess
+                    .struct_err(&format!(
+                        "error reading Clippy's configuration file `{}`: {}",
+                        file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""),
+                        error
+                    ))
+                    .emit();
             }
 
             conf
-        }
+        },
         Err((err, span)) => {
-            reg.sess.struct_span_err(span, err)
-                    .span_note(span, "Clippy will use default configuration")
-                    .emit();
+            reg.sess
+                .struct_span_err(span, err)
+                .span_note(span, "Clippy will use default configuration")
+                .emit();
             toml::from_str("").expect("we never error on empty config files")
-        }
-    };
+        },
+    }
+}
 
+/// Register all lints and lint groups with the rustc plugin registry
+///
+/// Used in `./src/driver.rs`.
+#[allow(clippy::too_many_lines)]
+#[rustfmt::skip]
+pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
     let mut store = reg.sess.lint_store.borrow_mut();
+    // begin deprecated lints, do not remove this comment, it’s used in `update_lints`
     store.register_removed(
         "should_assert_eq",
         "`assert!()` will be more flexible with RFC 2011",
@@ -259,14 +409,27 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         "misaligned_transmute",
         "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
     );
+    store.register_removed(
+        "assign_ops",
+        "using compound assignment operators (e.g., `+=`) is harmless",
+    );
+    store.register_removed(
+        "if_let_redundant_pattern_matching",
+        "this lint has been changed to redundant_pattern_matching",
+    );
+    store.register_removed(
+        "unsafe_vector_initialization",
+        "the replacement suggested by this lint had substantially different behavior",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
-    reg.register_late_lint_pass(box serde_api::Serde);
-    reg.register_early_lint_pass(box utils::internal_lints::Clippy);
+    reg.register_late_lint_pass(box serde_api::SerdeAPI);
+    reg.register_early_lint_pass(box utils::internal_lints::ClippyLintsInternal);
+    reg.register_late_lint_pass(box utils::internal_lints::CompilerLintFunctions::new());
     reg.register_late_lint_pass(box utils::internal_lints::LintWithoutLintPass::default());
-    reg.register_late_lint_pass(box utils::inspector::Pass);
-    reg.register_late_lint_pass(box utils::author::Pass);
-    reg.register_late_lint_pass(box types::TypePass);
+    reg.register_late_lint_pass(box utils::inspector::DeepCodeInspector);
+    reg.register_late_lint_pass(box utils::author::Author);
+    reg.register_late_lint_pass(box types::Types);
     reg.register_late_lint_pass(box booleans::NonminimalBool);
     reg.register_late_lint_pass(box eq_op::EqOp);
     reg.register_early_lint_pass(box enum_variants::EnumVariantNames::new(conf.enum_variant_name_threshold));
@@ -274,68 +437,68 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
     reg.register_late_lint_pass(box enum_clike::UnportableVariant);
     reg.register_late_lint_pass(box excessive_precision::ExcessivePrecision);
     reg.register_late_lint_pass(box bit_mask::BitMask::new(conf.verbose_bit_mask_threshold));
-    reg.register_late_lint_pass(box ptr::PointerPass);
+    reg.register_late_lint_pass(box ptr::Ptr);
     reg.register_late_lint_pass(box needless_bool::NeedlessBool);
     reg.register_late_lint_pass(box needless_bool::BoolComparison);
-    reg.register_late_lint_pass(box approx_const::Pass);
-    reg.register_late_lint_pass(box misc::Pass);
+    reg.register_late_lint_pass(box approx_const::ApproxConstant);
+    reg.register_late_lint_pass(box misc::MiscLints);
     reg.register_early_lint_pass(box precedence::Precedence);
     reg.register_early_lint_pass(box needless_continue::NeedlessContinue);
-    reg.register_late_lint_pass(box eta_reduction::EtaPass);
+    reg.register_late_lint_pass(box eta_reduction::EtaReduction);
     reg.register_late_lint_pass(box identity_op::IdentityOp);
     reg.register_late_lint_pass(box erasing_op::ErasingOp);
     reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatements);
     reg.register_late_lint_pass(box mut_mut::MutMut);
     reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed);
     reg.register_late_lint_pass(box len_zero::LenZero);
-    reg.register_late_lint_pass(box attrs::AttrPass);
+    reg.register_late_lint_pass(box attrs::Attributes);
     reg.register_early_lint_pass(box collapsible_if::CollapsibleIf);
     reg.register_late_lint_pass(box block_in_if_condition::BlockInIfCondition);
     reg.register_late_lint_pass(box unicode::Unicode);
     reg.register_late_lint_pass(box strings::StringAdd);
-    reg.register_early_lint_pass(box returns::ReturnPass);
-    reg.register_late_lint_pass(box methods::Pass);
-    reg.register_late_lint_pass(box shadow::Pass);
-    reg.register_late_lint_pass(box types::LetPass);
+    reg.register_early_lint_pass(box returns::Return);
+    reg.register_late_lint_pass(box implicit_return::ImplicitReturn);
+    reg.register_late_lint_pass(box methods::Methods);
+    reg.register_late_lint_pass(box map_clone::MapClone);
+    reg.register_late_lint_pass(box shadow::Shadow);
+    reg.register_late_lint_pass(box types::LetUnitValue);
     reg.register_late_lint_pass(box types::UnitCmp);
-    reg.register_late_lint_pass(box loops::Pass);
-    reg.register_late_lint_pass(box lifetimes::LifetimePass);
-    reg.register_late_lint_pass(box entry::HashMapLint);
-    reg.register_late_lint_pass(box ranges::Pass);
-    reg.register_late_lint_pass(box types::CastPass);
-    reg.register_late_lint_pass(box types::TypeComplexityPass::new(conf.type_complexity_threshold));
-    reg.register_late_lint_pass(box matches::MatchPass);
+    reg.register_late_lint_pass(box loops::Loops);
+    reg.register_late_lint_pass(box lifetimes::Lifetimes);
+    reg.register_late_lint_pass(box entry::HashMapPass);
+    reg.register_late_lint_pass(box ranges::Ranges);
+    reg.register_late_lint_pass(box types::Casts);
+    reg.register_late_lint_pass(box types::TypeComplexity::new(conf.type_complexity_threshold));
+    reg.register_late_lint_pass(box matches::Matches);
     reg.register_late_lint_pass(box minmax::MinMaxPass);
-    reg.register_late_lint_pass(box open_options::NonSensical);
-    reg.register_late_lint_pass(box zero_div_zero::Pass);
-    reg.register_late_lint_pass(box mutex_atomic::MutexAtomic);
-    reg.register_late_lint_pass(box needless_update::Pass);
-    reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow);
+    reg.register_late_lint_pass(box open_options::OpenOptions);
+    reg.register_late_lint_pass(box zero_div_zero::ZeroDiv);
+    reg.register_late_lint_pass(box mutex_atomic::Mutex);
+    reg.register_late_lint_pass(box needless_update::NeedlessUpdate);
+    reg.register_late_lint_pass(box needless_borrow::NeedlessBorrow::default());
     reg.register_late_lint_pass(box needless_borrowed_ref::NeedlessBorrowedRef);
-    reg.register_late_lint_pass(box no_effect::Pass);
-    reg.register_late_lint_pass(box map_clone::Pass);
-    reg.register_late_lint_pass(box temporary_assignment::Pass);
+    reg.register_late_lint_pass(box no_effect::NoEffect);
+    reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignment);
     reg.register_late_lint_pass(box transmute::Transmute);
     reg.register_late_lint_pass(
-        box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold)
+        box cognitive_complexity::CognitiveComplexity::new(conf.cognitive_complexity_threshold)
     );
-    reg.register_late_lint_pass(box escape::Pass{too_large_for_stack: conf.too_large_for_stack});
-    reg.register_early_lint_pass(box misc_early::MiscEarly);
-    reg.register_late_lint_pass(box panic_unimplemented::Pass);
+    reg.register_late_lint_pass(box escape::BoxedLocal{too_large_for_stack: conf.too_large_for_stack});
+    reg.register_early_lint_pass(box misc_early::MiscEarlyLints);
+    reg.register_late_lint_pass(box panic_unimplemented::PanicUnimplemented);
     reg.register_late_lint_pass(box strings::StringLitAsBytes);
     reg.register_late_lint_pass(box derive::Derive);
     reg.register_late_lint_pass(box types::CharLitAsU8);
-    reg.register_late_lint_pass(box vec::Pass);
-    reg.register_early_lint_pass(box non_expressive_names::NonExpressiveNames {
-        single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
-    });
-    reg.register_late_lint_pass(box drop_forget_ref::Pass);
+    reg.register_late_lint_pass(box vec::UselessVec);
+    reg.register_late_lint_pass(box drop_bounds::DropBounds);
+    reg.register_late_lint_pass(box drop_forget_ref::DropForgetRef);
     reg.register_late_lint_pass(box empty_enum::EmptyEnum);
     reg.register_late_lint_pass(box types::AbsurdExtremeComparisons);
     reg.register_late_lint_pass(box types::InvalidUpcastComparisons);
-    reg.register_late_lint_pass(box regex::Pass::default());
+    reg.register_late_lint_pass(box regex::Regex::default());
     reg.register_late_lint_pass(box copies::CopyAndPaste);
-    reg.register_late_lint_pass(box format::Pass);
+    reg.register_late_lint_pass(box copy_iterator::CopyIterator);
+    reg.register_late_lint_pass(box format::UselessFormat);
     reg.register_early_lint_pass(box formatting::Formatting);
     reg.register_late_lint_pass(box swap::Swap);
     reg.register_early_lint_pass(box if_not_else::IfNotElse);
@@ -343,43 +506,45 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
     reg.register_early_lint_pass(box int_plus_one::IntPlusOne);
     reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional);
     reg.register_late_lint_pass(box unused_label::UnusedLabel);
-    reg.register_late_lint_pass(box new_without_default::NewWithoutDefault);
-    reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names));
-    reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold));
-    reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents));
+    reg.register_late_lint_pass(box new_without_default::NewWithoutDefault::default());
+    reg.register_late_lint_pass(box blacklisted_name::BlacklistedName::new(
+            conf.blacklisted_names.iter().cloned().collect()
+    ));
+    reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold, conf.too_many_lines_threshold));
+    reg.register_early_lint_pass(box doc::DocMarkdown::new(conf.doc_valid_idents.iter().cloned().collect()));
     reg.register_late_lint_pass(box neg_multiply::NegMultiply);
     reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval);
+    reg.register_late_lint_pass(box mem_discriminant::MemDiscriminant);
     reg.register_late_lint_pass(box mem_forget::MemForget);
+    reg.register_late_lint_pass(box mem_replace::MemReplace);
     reg.register_late_lint_pass(box arithmetic::Arithmetic::default());
     reg.register_late_lint_pass(box assign_ops::AssignOps);
     reg.register_late_lint_pass(box let_if_seq::LetIfSeq);
     reg.register_late_lint_pass(box eval_order_dependence::EvalOrderDependence);
     reg.register_late_lint_pass(box missing_doc::MissingDoc::new());
     reg.register_late_lint_pass(box missing_inline::MissingInline);
-    reg.register_late_lint_pass(box ok_if_let::Pass);
-    reg.register_late_lint_pass(box if_let_redundant_pattern_matching::Pass);
-    reg.register_late_lint_pass(box partialeq_ne_impl::Pass);
-    reg.register_early_lint_pass(box reference::Pass);
-    reg.register_early_lint_pass(box reference::DerefPass);
+    reg.register_late_lint_pass(box ok_if_let::OkIfLet);
+    reg.register_late_lint_pass(box redundant_pattern_matching::RedundantPatternMatching);
+    reg.register_late_lint_pass(box partialeq_ne_impl::PartialEqNeImpl);
+    reg.register_early_lint_pass(box reference::DerefAddrOf);
+    reg.register_early_lint_pass(box reference::RefInDeref);
     reg.register_early_lint_pass(box double_parens::DoubleParens);
     reg.register_late_lint_pass(box unused_io_amount::UnusedIoAmount);
     reg.register_late_lint_pass(box large_enum_variant::LargeEnumVariant::new(conf.enum_variant_size_threshold));
-    reg.register_late_lint_pass(box explicit_write::Pass);
+    reg.register_late_lint_pass(box explicit_write::ExplicitWrite);
     reg.register_late_lint_pass(box needless_pass_by_value::NeedlessPassByValue);
-
-    let target = &reg.sess.target;
     reg.register_late_lint_pass(box trivially_copy_pass_by_ref::TriviallyCopyPassByRef::new(
             conf.trivial_copy_size_limit,
-            target,
+            &reg.sess.target,
     ));
     reg.register_early_lint_pass(box literal_representation::LiteralDigitGrouping);
-    reg.register_early_lint_pass(box literal_representation::LiteralRepresentation::new(
+    reg.register_early_lint_pass(box literal_representation::DecimalLiteralRepresentation::new(
             conf.literal_representation_threshold
     ));
     reg.register_late_lint_pass(box use_self::UseSelf);
     reg.register_late_lint_pass(box bytecount::ByteCount);
-    reg.register_late_lint_pass(box infinite_iter::Pass);
-    reg.register_late_lint_pass(box inline_fn_without_body::Pass);
+    reg.register_late_lint_pass(box infinite_iter::InfiniteIter);
+    reg.register_late_lint_pass(box inline_fn_without_body::InlineFnWithoutBody);
     reg.register_late_lint_pass(box invalid_ref::InvalidRef);
     reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default());
     reg.register_late_lint_pass(box types::ImplicitHasher);
@@ -387,30 +552,43 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
     reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom);
     reg.register_late_lint_pass(box replace_consts::ReplaceConsts);
     reg.register_late_lint_pass(box types::UnitArg);
-    reg.register_late_lint_pass(box double_comparison::DoubleComparisonPass);
-    reg.register_late_lint_pass(box question_mark::QuestionMarkPass);
+    reg.register_late_lint_pass(box double_comparison::DoubleComparisons);
+    reg.register_late_lint_pass(box question_mark::QuestionMark);
     reg.register_late_lint_pass(box suspicious_trait_impl::SuspiciousImpl);
-    reg.register_late_lint_pass(box redundant_field_names::RedundantFieldNames);
-    reg.register_early_lint_pass(box multiple_crate_versions::Pass);
-    reg.register_late_lint_pass(box map_unit_fn::Pass);
-    reg.register_late_lint_pass(box infallible_destructuring_match::Pass);
-    reg.register_late_lint_pass(box inherent_impl::Pass::default());
+    reg.register_early_lint_pass(box cargo_common_metadata::CargoCommonMetadata);
+    reg.register_early_lint_pass(box multiple_crate_versions::MultipleCrateVersions);
+    reg.register_early_lint_pass(box wildcard_dependencies::WildcardDependencies);
+    reg.register_late_lint_pass(box map_unit_fn::MapUnit);
+    reg.register_late_lint_pass(box infallible_destructuring_match::InfallibleDestructingMatch);
+    reg.register_late_lint_pass(box inherent_impl::MultipleInherentImpl::default());
     reg.register_late_lint_pass(box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
-    reg.register_late_lint_pass(box unwrap::Pass);
+    reg.register_late_lint_pass(box unwrap::Unwrap);
     reg.register_late_lint_pass(box duration_subsec::DurationSubsec);
     reg.register_late_lint_pass(box default_trait_access::DefaultTraitAccess);
     reg.register_late_lint_pass(box indexing_slicing::IndexingSlicing);
     reg.register_late_lint_pass(box non_copy_const::NonCopyConst);
+    reg.register_late_lint_pass(box ptr_offset_with_cast::PtrOffsetWithCast);
+    reg.register_late_lint_pass(box redundant_clone::RedundantClone);
+    reg.register_late_lint_pass(box slow_vector_initialization::SlowVectorInit);
+    reg.register_late_lint_pass(box types::RefToMut);
+    reg.register_late_lint_pass(box assertions_on_constants::AssertionsOnConstants);
+    reg.register_late_lint_pass(box missing_const_for_fn::MissingConstForFn);
+    reg.register_late_lint_pass(box transmuting_null::TransmutingNull);
+    reg.register_late_lint_pass(box path_buf_push_overwrite::PathBufPushOverwrite);
 
-    reg.register_lint_group("clippy_restriction", vec![
+    reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![
         arithmetic::FLOAT_ARITHMETIC,
         arithmetic::INTEGER_ARITHMETIC,
-        assign_ops::ASSIGN_OPS,
+        dbg_macro::DBG_MACRO,
         else_if_without_else::ELSE_IF_WITHOUT_ELSE,
+        implicit_return::IMPLICIT_RETURN,
+        indexing_slicing::INDEXING_SLICING,
         inherent_impl::MULTIPLE_INHERENT_IMPL,
         literal_representation::DECIMAL_LITERAL_REPRESENTATION,
+        matches::WILDCARD_ENUM_MATCH_ARM,
         mem_forget::MEM_FORGET,
         methods::CLONE_ON_REF_PTR,
+        methods::GET_UNWRAP,
         methods::OPTION_UNWRAP_USED,
         methods::RESULT_UNWRAP_USED,
         methods::WRONG_PUB_SELF_CONVENTION,
@@ -420,28 +598,35 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         panic_unimplemented::UNIMPLEMENTED,
         shadow::SHADOW_REUSE,
         shadow::SHADOW_SAME,
-        shadow::SHADOW_UNRELATED,
         strings::STRING_ADD,
         write::PRINT_STDOUT,
         write::USE_DEBUG,
     ]);
 
-    reg.register_lint_group("clippy_pedantic", vec![
+    reg.register_lint_group("clippy::pedantic", Some("clippy_pedantic"), vec![
         attrs::INLINE_ALWAYS,
         copies::MATCH_SAME_ARMS,
+        copy_iterator::COPY_ITERATOR,
         default_trait_access::DEFAULT_TRAIT_ACCESS,
         derive::EXPL_IMPL_CLONE_ON_COPY,
         doc::DOC_MARKDOWN,
         empty_enum::EMPTY_ENUM,
         enum_glob_use::ENUM_GLOB_USE,
+        enum_variants::MODULE_NAME_REPETITIONS,
         enum_variants::PUB_ENUM_VARIANT_NAMES,
-        enum_variants::STUTTER,
+        eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+        functions::TOO_MANY_LINES,
         if_not_else::IF_NOT_ELSE,
-        indexing_slicing::INDEXING_SLICING,
         infinite_iter::MAYBE_INFINITE_ITER,
         items_after_statements::ITEMS_AFTER_STATEMENTS,
+        literal_representation::LARGE_DIGIT_GROUPS,
+        loops::EXPLICIT_INTO_ITER_LOOP,
+        loops::EXPLICIT_ITER_LOOP,
         matches::SINGLE_MATCH_ELSE,
         methods::FILTER_MAP,
+        methods::FILTER_MAP_NEXT,
+        methods::FIND_MAP,
+        methods::MAP_FLATTEN,
         methods::OPTION_MAP_UNWRAP_OR,
         methods::OPTION_MAP_UNWRAP_OR_ELSE,
         methods::RESULT_MAP_UNWRAP_OR_ELSE,
@@ -449,8 +634,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         misc_early::UNSEPARATED_LITERAL_SUFFIX,
         mut_mut::MUT_MUT,
         needless_continue::NEEDLESS_CONTINUE,
+        needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
         non_expressive_names::SIMILAR_NAMES,
         replace_consts::REPLACE_CONSTS,
+        shadow::SHADOW_UNRELATED,
         strings::STRING_ADD_ASSIGN,
         types::CAST_POSSIBLE_TRUNCATION,
         types::CAST_POSSIBLE_WRAP,
@@ -463,16 +650,20 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         use_self::USE_SELF,
     ]);
 
-    reg.register_lint_group("clippy_internal", vec![
+    reg.register_lint_group("clippy::internal", Some("clippy_internal"), vec![
         utils::internal_lints::CLIPPY_LINTS_INTERNAL,
+        utils::internal_lints::COMPILER_LINT_FUNCTIONS,
         utils::internal_lints::LINT_WITHOUT_LINT_PASS,
     ]);
 
-    reg.register_lint_group("clippy", vec![
+    reg.register_lint_group("clippy::all", Some("clippy"), vec![
         approx_const::APPROX_CONSTANT,
+        assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
         assign_ops::ASSIGN_OP_PATTERN,
         assign_ops::MISREFACTORED_ASSIGN_OP,
+        attrs::DEPRECATED_CFG_ATTR,
         attrs::DEPRECATED_SEMVER,
+        attrs::UNKNOWN_CLIPPY_LINTS,
         attrs::USELESS_ATTRIBUTE,
         bit_mask::BAD_BIT_MASK,
         bit_mask::INEFFECTIVE_BIT_MASK,
@@ -483,14 +674,15 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         booleans::LOGIC_BUG,
         booleans::NONMINIMAL_BOOL,
         bytecount::NAIVE_BYTECOUNT,
+        cognitive_complexity::COGNITIVE_COMPLEXITY,
         collapsible_if::COLLAPSIBLE_IF,
         const_static_lifetime::CONST_STATIC_LIFETIME,
-        copies::IF_SAME_THEN_ELSE,
         copies::IFS_SAME_COND,
-        cyclomatic_complexity::CYCLOMATIC_COMPLEXITY,
+        copies::IF_SAME_THEN_ELSE,
         derive::DERIVE_HASH_XOR_EQ,
         double_comparison::DOUBLE_COMPARISONS,
         double_parens::DOUBLE_PARENS,
+        drop_bounds::DROP_BOUNDS,
         drop_forget_ref::DROP_COPY,
         drop_forget_ref::DROP_REF,
         drop_forget_ref::FORGET_COPY,
@@ -517,7 +709,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         functions::TOO_MANY_ARGUMENTS,
         identity_conversion::IDENTITY_CONVERSION,
         identity_op::IDENTITY_OP,
-        if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
         indexing_slicing::OUT_OF_BOUNDS_INDEXING,
         infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH,
         infinite_iter::INFINITE_ITER,
@@ -531,18 +722,17 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         lifetimes::EXTRA_UNUSED_LIFETIMES,
         lifetimes::NEEDLESS_LIFETIMES,
         literal_representation::INCONSISTENT_DIGIT_GROUPING,
-        literal_representation::LARGE_DIGIT_GROUPS,
+        literal_representation::MISTYPED_LITERAL_SUFFIXES,
         literal_representation::UNREADABLE_LITERAL,
         loops::EMPTY_LOOP,
         loops::EXPLICIT_COUNTER_LOOP,
-        loops::EXPLICIT_INTO_ITER_LOOP,
-        loops::EXPLICIT_ITER_LOOP,
         loops::FOR_KV_MAP,
         loops::FOR_LOOP_OVER_OPTION,
         loops::FOR_LOOP_OVER_RESULT,
         loops::ITER_NEXT_LOOP,
         loops::MANUAL_MEMCPY,
         loops::MUT_RANGE_BOUND,
+        loops::NEEDLESS_COLLECT,
         loops::NEEDLESS_RANGE_LOOP,
         loops::NEVER_LOOP,
         loops::REVERSE_RANGE_LOOP,
@@ -559,13 +749,16 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         matches::MATCH_REF_PATS,
         matches::MATCH_WILD_ERR_ARM,
         matches::SINGLE_MATCH,
+        mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
+        mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
         methods::CHARS_LAST_CMP,
         methods::CHARS_NEXT_CMP,
         methods::CLONE_DOUBLE_REF,
         methods::CLONE_ON_COPY,
         methods::EXPECT_FUN_CALL,
         methods::FILTER_NEXT,
-        methods::GET_UNWRAP,
+        methods::INTO_ITER_ON_ARRAY,
+        methods::INTO_ITER_ON_REF,
         methods::ITER_CLONED_COLLECT,
         methods::ITER_NTH,
         methods::ITER_SKIP_NEXT,
@@ -578,6 +771,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         methods::SINGLE_CHAR_PATTERN,
         methods::STRING_EXTEND_CHARS,
         methods::TEMPORARY_CSTRING_AS_PTR,
+        methods::UNNECESSARY_FILTER_MAP,
         methods::UNNECESSARY_FOLD,
         methods::USELESS_ASREF,
         methods::WRONG_SELF_CONVENTION,
@@ -602,12 +796,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         needless_bool::BOOL_COMPARISON,
         needless_bool::NEEDLESS_BOOL,
         needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
-        needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
         needless_update::NEEDLESS_UPDATE,
         neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD,
         neg_multiply::NEG_MULTIPLY,
         new_without_default::NEW_WITHOUT_DEFAULT,
-        new_without_default::NEW_WITHOUT_DEFAULT_DERIVE,
         no_effect::NO_EFFECT,
         no_effect::UNNECESSARY_OPERATION,
         non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
@@ -623,11 +815,14 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         ptr::CMP_NULL,
         ptr::MUT_FROM_REF,
         ptr::PTR_ARG,
+        ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
         question_mark::QUESTION_MARK,
         ranges::ITERATOR_STEP_BY_ZERO,
         ranges::RANGE_MINUS_ONE,
+        ranges::RANGE_PLUS_ONE,
         ranges::RANGE_ZIP_WITH_LEN,
         redundant_field_names::REDUNDANT_FIELD_NAMES,
+        redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING,
         reference::DEREF_ADDROF,
         reference::REF_IN_DEREF,
         regex::INVALID_REGEX,
@@ -635,7 +830,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         regex::TRIVIAL_REGEX,
         returns::LET_AND_RETURN,
         returns::NEEDLESS_RETURN,
+        returns::UNUSED_UNIT,
         serde_api::SERDE_API_MISUSE,
+        slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
         strings::STRING_LIT_AS_BYTES,
         suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
         suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
@@ -651,12 +848,14 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         transmute::TRANSMUTE_PTR_TO_REF,
         transmute::USELESS_TRANSMUTE,
         transmute::WRONG_TRANSMUTE,
+        transmuting_null::TRANSMUTING_NULL,
         trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF,
         types::ABSURD_EXTREME_COMPARISONS,
         types::BORROWED_BOX,
         types::BOX_VEC,
         types::CAST_LOSSLESS,
         types::CAST_PTR_ALIGNMENT,
+        types::CAST_REF_TO_MUT,
         types::CHAR_LIT_AS_U8,
         types::FN_TO_NUMERIC_CAST,
         types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
@@ -667,22 +866,25 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         types::UNIT_ARG,
         types::UNIT_CMP,
         types::UNNECESSARY_CAST,
+        types::VEC_BOX,
         unicode::ZERO_WIDTH_SPACE,
         unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
         unused_io_amount::UNUSED_IO_AMOUNT,
         unused_label::UNUSED_LABEL,
         vec::USELESS_VEC,
+        write::PRINTLN_EMPTY_STRING,
         write::PRINT_LITERAL,
         write::PRINT_WITH_NEWLINE,
-        write::PRINTLN_EMPTY_STRING,
+        write::WRITELN_EMPTY_STRING,
         write::WRITE_LITERAL,
         write::WRITE_WITH_NEWLINE,
-        write::WRITELN_EMPTY_STRING,
         zero_div_zero::ZERO_DIVIDED_BY_ZERO,
     ]);
 
-    reg.register_lint_group("clippy_style", vec![
+    reg.register_lint_group("clippy::style", Some("clippy_style"), vec![
+        assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
         assign_ops::ASSIGN_OP_PATTERN,
+        attrs::UNKNOWN_CLIPPY_LINTS,
         bit_mask::VERBOSE_BIT_MASK,
         blacklisted_name::BLACKLISTED_NAME,
         block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR,
@@ -696,17 +898,13 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         excessive_precision::EXCESSIVE_PRECISION,
         formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
         formatting::SUSPICIOUS_ELSE_FORMATTING,
-        if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
         infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH,
         len_zero::LEN_WITHOUT_IS_EMPTY,
         len_zero::LEN_ZERO,
         let_if_seq::USELESS_LET_IF_SEQ,
         literal_representation::INCONSISTENT_DIGIT_GROUPING,
-        literal_representation::LARGE_DIGIT_GROUPS,
         literal_representation::UNREADABLE_LITERAL,
         loops::EMPTY_LOOP,
-        loops::EXPLICIT_INTO_ITER_LOOP,
-        loops::EXPLICIT_ITER_LOOP,
         loops::FOR_KV_MAP,
         loops::NEEDLESS_RANGE_LOOP,
         loops::WHILE_LET_ON_ITERATOR,
@@ -716,8 +914,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         matches::MATCH_REF_PATS,
         matches::MATCH_WILD_ERR_ARM,
         matches::SINGLE_MATCH,
+        mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
         methods::CHARS_LAST_CMP,
-        methods::GET_UNWRAP,
+        methods::INTO_ITER_ON_REF,
         methods::ITER_CLONED_COLLECT,
         methods::ITER_SKIP_NEXT,
         methods::NEW_RET_NO_SELF,
@@ -736,10 +935,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         misc_early::MIXED_CASE_HEX_LITERALS,
         misc_early::UNNEEDED_FIELD_PATTERN,
         mut_reference::UNNECESSARY_MUT_PASSED,
-        needless_pass_by_value::NEEDLESS_PASS_BY_VALUE,
         neg_multiply::NEG_MULTIPLY,
         new_without_default::NEW_WITHOUT_DEFAULT,
-        new_without_default::NEW_WITHOUT_DEFAULT_DERIVE,
         non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
         non_expressive_names::MANY_SINGLE_CHAR_NAMES,
         ok_if_let::IF_LET_SOME_RESULT,
@@ -747,29 +944,32 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         ptr::CMP_NULL,
         ptr::PTR_ARG,
         question_mark::QUESTION_MARK,
-        ranges::RANGE_MINUS_ONE,
         redundant_field_names::REDUNDANT_FIELD_NAMES,
+        redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING,
         regex::REGEX_MACRO,
         regex::TRIVIAL_REGEX,
         returns::LET_AND_RETURN,
         returns::NEEDLESS_RETURN,
+        returns::UNUSED_UNIT,
         strings::STRING_LIT_AS_BYTES,
         types::FN_TO_NUMERIC_CAST,
+        types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
         types::IMPLICIT_HASHER,
         types::LET_UNIT_VALUE,
         unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
+        write::PRINTLN_EMPTY_STRING,
         write::PRINT_LITERAL,
         write::PRINT_WITH_NEWLINE,
-        write::PRINTLN_EMPTY_STRING,
+        write::WRITELN_EMPTY_STRING,
         write::WRITE_LITERAL,
         write::WRITE_WITH_NEWLINE,
-        write::WRITELN_EMPTY_STRING,
     ]);
 
-    reg.register_lint_group("clippy_complexity", vec![
+    reg.register_lint_group("clippy::complexity", Some("clippy_complexity"), vec![
         assign_ops::MISREFACTORED_ASSIGN_OP,
+        attrs::DEPRECATED_CFG_ATTR,
         booleans::NONMINIMAL_BOOL,
-        cyclomatic_complexity::CYCLOMATIC_COMPLEXITY,
+        cognitive_complexity::COGNITIVE_COMPLEXITY,
         double_comparison::DOUBLE_COMPARISONS,
         double_parens::DOUBLE_PARENS,
         duration_subsec::DURATION_SUBSEC,
@@ -793,6 +993,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         methods::CLONE_ON_COPY,
         methods::FILTER_NEXT,
         methods::SEARCH_IS_SOME,
+        methods::UNNECESSARY_FILTER_MAP,
         methods::USELESS_ASREF,
         misc::SHORT_CIRCUIT_STATEMENT,
         misc_early::REDUNDANT_CLOSURE_CALL,
@@ -807,6 +1008,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
         partialeq_ne_impl::PARTIALEQ_NE_IMPL,
         precedence::PRECEDENCE,
+        ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
+        ranges::RANGE_MINUS_ONE,
+        ranges::RANGE_PLUS_ONE,
         ranges::RANGE_ZIP_WITH_LEN,
         reference::DEREF_ADDROF,
         reference::REF_IN_DEREF,
@@ -827,20 +1031,22 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         types::TYPE_COMPLEXITY,
         types::UNIT_ARG,
         types::UNNECESSARY_CAST,
+        types::VEC_BOX,
         unused_label::UNUSED_LABEL,
         zero_div_zero::ZERO_DIVIDED_BY_ZERO,
     ]);
 
-    reg.register_lint_group("clippy_correctness", vec![
+    reg.register_lint_group("clippy::correctness", Some("clippy_correctness"), vec![
         approx_const::APPROX_CONSTANT,
         attrs::DEPRECATED_SEMVER,
         attrs::USELESS_ATTRIBUTE,
         bit_mask::BAD_BIT_MASK,
         bit_mask::INEFFECTIVE_BIT_MASK,
         booleans::LOGIC_BUG,
-        copies::IF_SAME_THEN_ELSE,
         copies::IFS_SAME_COND,
+        copies::IF_SAME_THEN_ELSE,
         derive::DERIVE_HASH_XOR_EQ,
+        drop_bounds::DROP_BOUNDS,
         drop_forget_ref::DROP_COPY,
         drop_forget_ref::DROP_REF,
         drop_forget_ref::FORGET_COPY,
@@ -854,13 +1060,16 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         infinite_iter::INFINITE_ITER,
         inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
         invalid_ref::INVALID_REF,
+        literal_representation::MISTYPED_LITERAL_SUFFIXES,
         loops::FOR_LOOP_OVER_OPTION,
         loops::FOR_LOOP_OVER_RESULT,
         loops::ITER_NEXT_LOOP,
         loops::NEVER_LOOP,
         loops::REVERSE_RANGE_LOOP,
         loops::WHILE_IMMUTABLE_CONDITION,
+        mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
         methods::CLONE_DOUBLE_REF,
+        methods::INTO_ITER_ON_ARRAY,
         methods::TEMPORARY_CSTRING_AS_PTR,
         minmax::MIN_MAX,
         misc::CMP_NAN,
@@ -877,20 +1086,22 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
         swap::ALMOST_SWAPPED,
         transmute::WRONG_TRANSMUTE,
+        transmuting_null::TRANSMUTING_NULL,
         types::ABSURD_EXTREME_COMPARISONS,
         types::CAST_PTR_ALIGNMENT,
-        types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+        types::CAST_REF_TO_MUT,
         types::UNIT_CMP,
         unicode::ZERO_WIDTH_SPACE,
         unused_io_amount::UNUSED_IO_AMOUNT,
     ]);
 
-    reg.register_lint_group("clippy_perf", vec![
+    reg.register_lint_group("clippy::perf", Some("clippy_perf"), vec![
         bytecount::NAIVE_BYTECOUNT,
         entry::MAP_ENTRY,
         escape::BOXED_LOCAL,
         large_enum_variant::LARGE_ENUM_VARIANT,
         loops::MANUAL_MEMCPY,
+        loops::NEEDLESS_COLLECT,
         loops::UNUSED_COLLECT,
         methods::EXPECT_FUN_CALL,
         methods::ITER_NTH,
@@ -898,29 +1109,43 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>) {
         methods::SINGLE_CHAR_PATTERN,
         misc::CMP_OWNED,
         mutex_atomic::MUTEX_ATOMIC,
+        slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
         trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF,
         types::BOX_VEC,
         vec::USELESS_VEC,
     ]);
 
-    reg.register_lint_group("clippy_cargo", vec![
+    reg.register_lint_group("clippy::cargo", Some("clippy_cargo"), vec![
+        cargo_common_metadata::CARGO_COMMON_METADATA,
         multiple_crate_versions::MULTIPLE_CRATE_VERSIONS,
+        wildcard_dependencies::WILDCARD_DEPENDENCIES,
     ]);
 
-    reg.register_lint_group("clippy_nursery", vec![
+    reg.register_lint_group("clippy::nursery", Some("clippy_nursery"), vec![
         attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
         fallible_impl_from::FALLIBLE_IMPL_FROM,
+        missing_const_for_fn::MISSING_CONST_FOR_FN,
         mutex_atomic::MUTEX_INTEGER,
         needless_borrow::NEEDLESS_BORROW,
-        ranges::RANGE_PLUS_ONE,
+        path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
+        redundant_clone::REDUNDANT_CLONE,
         unwrap::PANICKING_UNWRAP,
         unwrap::UNNECESSARY_UNWRAP,
     ]);
 }
 
+/// Register renamed lints.
+///
+/// Used in `./src/driver.rs`.
+pub fn register_renamed(ls: &mut rustc::lint::LintStore) {
+    ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
+    ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
+    ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
+}
+
 // only exists to let the dogfood integration test works.
 // Don't run clippy as an executable directly
-#[allow(dead_code, print_stdout)]
+#[allow(dead_code)]
 fn main() {
     panic!("Please use the cargo-clippy executable");
 }
index cf7a016231e347f41dfb829918e2d93b405bec9d..ff75fbaa55f223bcd51bf161ca613eab6b411fcb 100644 (file)
@@ -1,65 +1,63 @@
-use crate::reexport::*;
 use matches::matches;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::def::Def;
-use rustc::hir::*;
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::intravisit::*;
-use std::collections::{HashMap, HashSet};
-use syntax::codemap::Span;
-use crate::utils::{last_path_segment, span_lint};
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use syntax::source_map::Span;
 use syntax::symbol::keywords;
 
-/// **What it does:** Checks for lifetime annotations which can be removed by
-/// relying on lifetime elision.
-///
-/// **Why is this bad?** The additional lifetimes make the code look more
-/// complicated, while there is nothing out of the ordinary going on. Removing
-/// them leads to more readable code.
-///
-/// **Known problems:** Potential false negatives: we bail out if the function
-/// has a `where` clause where lifetimes are mentioned.
-///
-/// **Example:**
-/// ```rust
-/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x }
-/// ```
+use crate::reexport::*;
+use crate::utils::{last_path_segment, span_lint};
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for lifetime annotations which can be removed by
+    /// relying on lifetime elision.
+    ///
+    /// **Why is this bad?** The additional lifetimes make the code look more
+    /// complicated, while there is nothing out of the ordinary going on. Removing
+    /// them leads to more readable code.
+    ///
+    /// **Known problems:** Potential false negatives: we bail out if the function
+    /// has a `where` clause where lifetimes are mentioned.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
+    ///     x
+    /// }
+    /// ```
     pub NEEDLESS_LIFETIMES,
     complexity,
     "using explicit lifetimes for references in function arguments when elision rules \
      would allow omitting them"
 }
 
-/// **What it does:** Checks for lifetimes in generics that are never used
-/// anywhere else.
-///
-/// **Why is this bad?** The additional lifetimes make the code look more
-/// complicated, while there is nothing out of the ordinary going on. Removing
-/// them leads to more readable code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn unused_lifetime<'a>(x: u8) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for lifetimes in generics that are never used
+    /// anywhere else.
+    ///
+    /// **Why is this bad?** The additional lifetimes make the code look more
+    /// complicated, while there is nothing out of the ordinary going on. Removing
+    /// them leads to more readable code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn unused_lifetime<'a>(x: u8) {
+    ///     ..
+    /// }
+    /// ```
     pub EXTRA_UNUSED_LIFETIMES,
     complexity,
     "unused lifetimes in function definitions"
 }
 
-#[derive(Copy, Clone)]
-pub struct LifetimePass;
+declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 
-impl LintPass for LifetimePass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LifetimePass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if let ItemKind::Fn(ref decl, _, ref generics, id) = item.node {
             check_fn_inner(cx, decl, Some(id), generics, item.span);
@@ -103,9 +101,9 @@ fn check_fn_inner<'a, 'tcx>(
     }
 
     let mut bounds_lts = Vec::new();
-    let types = generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamKind::Type { .. } => Some(param),
-        GenericParamKind::Lifetime { .. } => None,
+    let types = generics.params.iter().filter(|param| match param.kind {
+        GenericParamKind::Type { .. } => true,
+        _ => false,
     });
     for typ in types {
         for bound in &typ.bounds {
@@ -125,7 +123,7 @@ fn check_fn_inner<'a, 'tcx>(
                 if let Some(ref params) = *params {
                     let lifetimes = params.args.iter().filter_map(|arg| match arg {
                         GenericArg::Lifetime(lt) => Some(lt),
-                        GenericArg::Type(_) => None,
+                        _ => None,
                     });
                     for bound in lifetimes {
                         if bound.name != LifetimeName::Static && !bound.is_elided() {
@@ -142,7 +140,8 @@ fn check_fn_inner<'a, 'tcx>(
             cx,
             NEEDLESS_LIFETIMES,
             span,
-            "explicit lifetimes given in parameter types where they could be elided",
+            "explicit lifetimes given in parameter types where they could be elided \
+             (or replaced with `'_` if needed by type declaration)",
         );
     }
     report_extra_lifetimes(cx, decl, generics);
@@ -190,7 +189,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
         let mut checker = BodyLifetimeChecker {
             lifetimes_used_in_body: false,
         };
-        checker.visit_expr(&cx.tcx.hir.body(body_id).value);
+        checker.visit_expr(&cx.tcx.hir().body(body_id).value);
         if checker.lifetimes_used_in_body {
             return false;
         }
@@ -210,9 +209,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
         // no output lifetimes, check distinctness of input lifetimes
 
         // only unnamed and static, ok
-        let unnamed_and_static = input_lts
-            .iter()
-            .all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
+        let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
         if unnamed_and_static {
             return false;
         }
@@ -237,8 +234,8 @@ fn could_use_elision<'a, 'tcx: 'a>(
     }
 }
 
-fn allowed_lts_from(named_generics: &[GenericParam]) -> HashSet<RefLt> {
-    let mut allowed_lts = HashSet::new();
+fn allowed_lts_from(named_generics: &[GenericParam]) -> FxHashSet<RefLt> {
+    let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
         if let GenericParamKind::Lifetime { .. } = par.kind {
             if par.bounds.is_empty() {
@@ -263,7 +260,7 @@ fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bo
 
 /// Number of unique lifetimes in the given vector.
 fn unique_lifetimes(lts: &[RefLt]) -> usize {
-    lts.iter().collect::<HashSet<_>>().len()
+    lts.iter().collect::<FxHashSet<_>>().len()
 }
 
 /// A visitor usable for `rustc_front::visit::walk_ty()`.
@@ -309,17 +306,18 @@ fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) {
             if !last_path_segment.parenthesized
                 && !last_path_segment.args.iter().any(|arg| match arg {
                     GenericArg::Lifetime(_) => true,
-                    GenericArg::Type(_) => false,
-                }) {
-                let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
-                match self.cx.tables.qpath_def(qpath, hir_id) {
-                    Def::TyAlias(def_id) | Def::Struct(def_id) => {
+                    _ => false,
+                })
+            {
+                let hir_id = ty.hir_id;
+                match self.cx.tables.qpath_res(qpath, hir_id) {
+                    Res::Def(DefKind::TyAlias, def_id) | Res::Def(DefKind::Struct, def_id) => {
                         let generics = self.cx.tcx.generics_of(def_id);
                         for _ in generics.params.as_slice() {
                             self.record(&None);
                         }
                     },
-                    Def::Trait(def_id) => {
+                    Res::Def(DefKind::Trait, def_id) => {
                         let trait_def = self.cx.tcx.trait_def(def_id);
                         for _ in &self.cx.tcx.generics_of(trait_def.def_id).params {
                             self.record(&None);
@@ -344,24 +342,21 @@ fn visit_ty(&mut self, ty: &'tcx Ty) {
                 self.record(&None);
             },
             TyKind::Path(ref path) => {
-                if let QPath::Resolved(_, ref path) = *path {
-                    if let Def::Existential(def_id) = path.def {
-                        let node_id = self.cx.tcx.hir.as_local_node_id(def_id).unwrap();
-                        if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir.expect_item(node_id).node {
-                            for bound in &exist_ty.bounds {
-                                if let GenericBound::Outlives(_) = *bound {
-                                    self.record(&None);
-                                }
-                            }
-                        } else {
-                            unreachable!()
+                self.collect_anonymous_lifetimes(path, ty);
+            },
+            TyKind::Def(item, _) => {
+                let map = self.cx.tcx.hir();
+                if let ItemKind::Existential(ref exist_ty) = map.expect_item(map.hir_to_node_id(item.id)).node {
+                    for bound in &exist_ty.bounds {
+                        if let GenericBound::Outlives(_) = *bound {
+                            self.record(&None);
                         }
-                        walk_ty(self, ty);
-                        return;
                     }
+                } else {
+                    unreachable!()
                 }
-                self.collect_anonymous_lifetimes(path, ty);
-            }
+                walk_ty(self, ty);
+            },
             TyKind::TraitObject(ref bounds, ref lt) => {
                 if !lt.is_elided() {
                     self.abort = true;
@@ -380,7 +375,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
+/// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
 /// reason about elision.
 fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &'tcx WhereClause) -> bool {
     for predicate in &where_clause.predicates {
@@ -403,9 +398,11 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
                 // and check that all lifetimes are allowed
                 match visitor.into_vec() {
                     None => return false,
-                    Some(lts) => for lt in lts {
-                        if !allowed_lts.contains(&lt) {
-                            return true;
+                    Some(lts) => {
+                        for lt in lts {
+                            if !allowed_lts.contains(&lt) {
+                                return true;
+                            }
                         }
                     },
                 }
@@ -424,7 +421,7 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
 }
 
 struct LifetimeChecker {
-    map: HashMap<Name, Span>,
+    map: FxHashMap<Name, Span>,
 }
 
 impl<'tcx> Visitor<'tcx> for LifetimeChecker {
@@ -449,7 +446,9 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 }
 
 fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
-    let hs = generics.params.iter()
+    let hs = generics
+        .params
+        .iter()
         .filter_map(|par| match par.kind {
             GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
             _ => None,
@@ -461,7 +460,12 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx
     walk_fn_decl(&mut checker, func);
 
     for &v in checker.map.values() {
-        span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition");
+        span_lint(
+            cx,
+            EXTRA_UNUSED_LIFETIMES,
+            v,
+            "this lifetime isn't used in the function definition",
+        );
     }
 }
 
@@ -472,7 +476,9 @@ struct BodyLifetimeChecker {
 impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
-        if lifetime.name.ident().name != keywords::Invalid.name() && lifetime.name.ident().name != "'static" {
+        if lifetime.name.ident().name != keywords::Invalid.name()
+            && lifetime.name.ident().name != syntax::symbol::keywords::StaticLifetime.name()
+        {
             self.lifetimes_used_in_body = true;
         }
     }
index 45f9af49a15fe279cadc8d8211be17272c46ff3e..004e9f14b580ab5f2153b2865f52e1349bdcfede 100644 (file)
 //! Lints concerned with the grouping of digits with underscores in integral or
 //! floating-point literal expressions.
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{snippet_opt, span_lint_and_sugg};
 use if_chain::if_chain;
+use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
 use syntax::ast::*;
 use syntax_pos;
-use crate::utils::{snippet_opt, span_lint_and_sugg};
 
-/// **What it does:** Warns if a long integral or floating-point constant does
-/// not contain underscores.
-///
-/// **Why is this bad?** Reading long numbers is difficult without separators.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 61864918973511
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Warns if a long integral or floating-point constant does
+    /// not contain underscores.
+    ///
+    /// **Why is this bad?** Reading long numbers is difficult without separators.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x: u64 = 61864918973511;
+    /// ```
     pub UNREADABLE_LITERAL,
     style,
     "long integer literal without underscores"
 }
 
-/// **What it does:** Warns if an integral or floating-point constant is
-/// grouped inconsistently with underscores.
-///
-/// **Why is this bad?** Readers may incorrectly interpret inconsistently
-/// grouped digits.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 618_64_9189_73_511
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Warns for mistyped suffix in literals
+    ///
+    /// **Why is this bad?** This is most probably a typo
+    ///
+    /// **Known problems:**
+    ///                - Recommends a signed suffix, even though the number might be too big and an unsigned
+    ///                suffix is required
+    ///                - Does not match on `_128` since that is a valid grouping for decimal and octal numbers
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// 2_32;
+    /// ```
+    pub MISTYPED_LITERAL_SUFFIXES,
+    correctness,
+    "mistyped literal suffix"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Warns if an integral or floating-point constant is
+    /// grouped inconsistently with underscores.
+    ///
+    /// **Why is this bad?** Readers may incorrectly interpret inconsistently
+    /// grouped digits.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x: u64 = 618_64_9189_73_511;
+    /// ```
     pub INCONSISTENT_DIGIT_GROUPING,
     style,
     "integer literals with digits grouped inconsistently"
 }
 
-/// **What it does:** Warns if the digits of an integral or floating-point
-/// constant are grouped into groups that
-/// are too large.
-///
-/// **Why is this bad?** Negatively impacts readability.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 6186491_8973511
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Warns if the digits of an integral or floating-point
+    /// constant are grouped into groups that
+    /// are too large.
+    ///
+    /// **Why is this bad?** Negatively impacts readability.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x: u64 = 6186491_8973511;
+    /// ```
     pub LARGE_DIGIT_GROUPS,
-    style,
+    pedantic,
     "grouping digits into groups that are too large"
 }
 
-/// **What it does:** Warns if there is a better representation for a numeric literal.
-///
-/// **Why is this bad?** Especially for big powers of 2 a hexadecimal representation is more
-/// readable than a decimal representation.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// `255` => `0xFF`
-/// `65_535` => `0xFFFF`
-/// `4_042_322_160` => `0xF0F0_F0F0`
 declare_clippy_lint! {
+    /// **What it does:** Warns if there is a better representation for a numeric literal.
+    ///
+    /// **Why is this bad?** Especially for big powers of 2 a hexadecimal representation is more
+    /// readable than a decimal representation.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// `255` => `0xFF`
+    /// `65_535` => `0xFFFF`
+    /// `4_042_322_160` => `0xF0F0_F0F0`
     pub DECIMAL_LITERAL_REPRESENTATION,
     restriction,
     "using decimal representation when hexadecimal would be better"
@@ -91,7 +112,7 @@ pub(super) enum Radix {
 }
 
 impl Radix {
-    /// Return a reasonable digit group size for this radix.
+    /// Returns a reasonable digit group size for this radix.
     crate fn suggest_grouping(&self) -> usize {
         match *self {
             Radix::Binary | Radix::Hexadecimal => 4,
@@ -135,10 +156,16 @@ impl<'a> DigitInfo<'a> {
             (Some(p), s)
         };
 
+        let len = sans_prefix.len();
         let mut last_d = '\0';
         for (d_idx, d) in sans_prefix.char_indices() {
-            if !float && (d == 'i' || d == 'u') || float && (d == 'f' || d == 'e' || d == 'E') {
-                let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx };
+            let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx };
+            if float
+                && (d == 'f'
+                    || is_possible_float_suffix_index(&sans_prefix, suffix_start, len)
+                    || ((d == 'E' || d == 'e') && !has_possible_float_suffix(&sans_prefix)))
+                || !float && (d == 'i' || d == 'u' || is_possible_suffix_index(&sans_prefix, suffix_start, len))
+            {
                 let (digits, suffix) = sans_prefix.split_at(suffix_start);
                 return Self {
                     digits,
@@ -161,7 +188,7 @@ impl<'a> DigitInfo<'a> {
         }
     }
 
-    /// Returns digits grouped in a sensible way.
+    /// Returns literal formatted in a sensible way.
     crate fn grouping_hint(&self) -> String {
         let group_size = self.radix.suggest_grouping();
         if self.digits.contains('.') {
@@ -174,7 +201,7 @@ impl<'a> DigitInfo<'a> {
                 .filter(|&c| c != '_')
                 .collect::<Vec<_>>()
                 .chunks(group_size)
-                .map(|chunk| chunk.into_iter().rev().collect())
+                .map(|chunk| chunk.iter().rev().collect())
                 .rev()
                 .collect::<Vec<String>>()
                 .join("_");
@@ -185,24 +212,50 @@ impl<'a> DigitInfo<'a> {
                 .filter(|&c| c != '_')
                 .collect::<Vec<_>>()
                 .chunks(group_size)
-                .map(|chunk| chunk.into_iter().collect())
+                .map(|chunk| chunk.iter().collect())
                 .collect::<Vec<String>>()
                 .join("_");
+            let suffix_hint = match self.suffix {
+                Some(suffix) if is_mistyped_float_suffix(suffix) => format!("_f{}", &suffix[1..]),
+                Some(suffix) => suffix.to_string(),
+                None => String::new(),
+            };
+            format!("{}.{}{}", int_part_hint, frac_part_hint, suffix_hint)
+        } else if self.float && (self.digits.contains('E') || self.digits.contains('e')) {
+            let which_e = if self.digits.contains('E') { 'E' } else { 'e' };
+            let parts: Vec<&str> = self.digits.split(which_e).collect();
+            let filtered_digits_vec_0 = parts[0].chars().filter(|&c| c != '_').rev().collect::<Vec<_>>();
+            let filtered_digits_vec_1 = parts[1].chars().filter(|&c| c != '_').rev().collect::<Vec<_>>();
+            let before_e_hint = filtered_digits_vec_0
+                .chunks(group_size)
+                .map(|chunk| chunk.iter().rev().collect())
+                .rev()
+                .collect::<Vec<String>>()
+                .join("_");
+            let after_e_hint = filtered_digits_vec_1
+                .chunks(group_size)
+                .map(|chunk| chunk.iter().rev().collect())
+                .rev()
+                .collect::<Vec<String>>()
+                .join("_");
+            let suffix_hint = match self.suffix {
+                Some(suffix) if is_mistyped_float_suffix(suffix) => format!("_f{}", &suffix[1..]),
+                Some(suffix) => suffix.to_string(),
+                None => String::new(),
+            };
             format!(
-                "{}.{}{}",
-                int_part_hint,
-                frac_part_hint,
-                self.suffix.unwrap_or("")
+                "{}{}{}{}{}",
+                self.prefix.unwrap_or(""),
+                before_e_hint,
+                which_e,
+                after_e_hint,
+                suffix_hint
             )
         } else {
-            let filtered_digits_vec = self.digits
-                .chars()
-                .filter(|&c| c != '_')
-                .rev()
-                .collect::<Vec<_>>();
+            let filtered_digits_vec = self.digits.chars().filter(|&c| c != '_').rev().collect::<Vec<_>>();
             let mut hint = filtered_digits_vec
                 .chunks(group_size)
-                .map(|chunk| chunk.into_iter().rev().collect())
+                .map(|chunk| chunk.iter().rev().collect())
                 .rev()
                 .collect::<Vec<String>>()
                 .join("_");
@@ -211,12 +264,12 @@ impl<'a> DigitInfo<'a> {
             if self.radix == Radix::Hexadecimal && nb_digits_to_fill != 0 {
                 hint = format!("{:0>4}{}", &hint[..nb_digits_to_fill], &hint[nb_digits_to_fill..]);
             }
-            format!(
-                "{}{}{}",
-                self.prefix.unwrap_or(""),
-                hint,
-                self.suffix.unwrap_or("")
-            )
+            let suffix_hint = match self.suffix {
+                Some(suffix) if is_mistyped_suffix(suffix) => format!("_i{}", &suffix[1..]),
+                Some(suffix) => suffix.to_string(),
+                None => String::new(),
+            };
+            format!("{}{}{}", self.prefix.unwrap_or(""), hint, suffix_hint)
         }
     }
 }
@@ -226,11 +279,21 @@ enum WarningType {
     InconsistentDigitGrouping,
     LargeDigitGroups,
     DecimalRepresentation,
+    MistypedLiteralSuffix,
 }
 
 impl WarningType {
     crate fn display(&self, grouping_hint: &str, cx: &EarlyContext<'_>, span: syntax_pos::Span) {
         match self {
+            WarningType::MistypedLiteralSuffix => span_lint_and_sugg(
+                cx,
+                MISTYPED_LITERAL_SUFFIXES,
+                span,
+                "mistyped literal suffix",
+                "did you mean to write",
+                grouping_hint.to_string(),
+                Applicability::MaybeIncorrect,
+            ),
             WarningType::UnreadableLiteral => span_lint_and_sugg(
                 cx,
                 UNREADABLE_LITERAL,
@@ -238,6 +301,7 @@ impl WarningType {
                 "long literal lacking separators",
                 "consider",
                 grouping_hint.to_owned(),
+                Applicability::MachineApplicable,
             ),
             WarningType::LargeDigitGroups => span_lint_and_sugg(
                 cx,
@@ -246,6 +310,7 @@ impl WarningType {
                 "digit groups should be smaller",
                 "consider",
                 grouping_hint.to_owned(),
+                Applicability::MachineApplicable,
             ),
             WarningType::InconsistentDigitGrouping => span_lint_and_sugg(
                 cx,
@@ -254,6 +319,7 @@ impl WarningType {
                 "digits grouped inconsistently by underscores",
                 "consider",
                 grouping_hint.to_owned(),
+                Applicability::MachineApplicable,
             ),
             WarningType::DecimalRepresentation => span_lint_and_sugg(
                 cx,
@@ -262,23 +328,18 @@ impl WarningType {
                 "integer literal has a better hexadecimal representation",
                 "consider",
                 grouping_hint.to_owned(),
+                Applicability::MachineApplicable,
             ),
         };
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct LiteralDigitGrouping;
-
-impl LintPass for LiteralDigitGrouping {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            UNREADABLE_LITERAL,
-            INCONSISTENT_DIGIT_GROUPING,
-            LARGE_DIGIT_GROUPS
-        )
-    }
-}
+declare_lint_pass!(LiteralDigitGrouping => [
+    UNREADABLE_LITERAL,
+    INCONSISTENT_DIGIT_GROUPING,
+    LARGE_DIGIT_GROUPS,
+    MISTYPED_LITERAL_SUFFIXES,
+]);
 
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
@@ -303,7 +364,7 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
                     if char::to_digit(firstch, 10).is_some();
                     then {
                         let digit_info = DigitInfo::new(&src, false);
-                        let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
+                        let _ = Self::do_lint(digit_info.digits, digit_info.suffix).map_err(|warning_type| {
                             warning_type.display(&digit_info.grouping_hint(), cx, lit.span)
                         });
                     }
@@ -325,22 +386,24 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
 
                         // Lint integral and fractional parts separately, and then check consistency of digit
                         // groups if both pass.
-                        let _ = Self::do_lint(parts[0])
+                        let _ = Self::do_lint(parts[0], digit_info.suffix)
                             .map(|integral_group_size| {
                                 if parts.len() > 1 {
                                     // Lint the fractional part of literal just like integral part, but reversed.
                                     let fractional_part = &parts[1].chars().rev().collect::<String>();
-                                    let _ = Self::do_lint(fractional_part)
+                                    let _ = Self::do_lint(fractional_part, None)
                                         .map(|fractional_group_size| {
                                             let consistent = Self::parts_consistent(integral_group_size,
                                                                                     fractional_group_size,
                                                                                     parts[0].len(),
                                                                                     parts[1].len());
-                                            if !consistent {
-                                                WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
-                                                cx,
-                                                lit.span);
-                                            }
+                                                if !consistent {
+                                                    WarningType::InconsistentDigitGrouping.display(
+                                                        &digit_info.grouping_hint(),
+                                                        cx,
+                                                        lit.span,
+                                                    );
+                                                }
                                         })
                                     .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),
                                     cx,
@@ -373,7 +436,12 @@ fn parts_consistent(int_group_size: usize, frac_group_size: usize, int_size: usi
 
     /// Performs lint on `digits` (no decimal point) and returns the group
     /// size on success or `WarningType` when emitting a warning.
-    fn do_lint(digits: &str) -> Result<usize, WarningType> {
+    fn do_lint(digits: &str, suffix: Option<&str>) -> Result<usize, WarningType> {
+        if let Some(suffix) = suffix {
+            if is_mistyped_suffix(suffix) {
+                return Err(WarningType::MistypedLiteralSuffix);
+            }
+        }
         // Grab underscore indices with respect to the units digit.
         let underscore_positions: Vec<usize> = digits
             .chars()
@@ -409,18 +477,15 @@ fn do_lint(digits: &str) -> Result<usize, WarningType> {
     }
 }
 
+#[allow(clippy::module_name_repetitions)]
 #[derive(Copy, Clone)]
-pub struct LiteralRepresentation {
+pub struct DecimalLiteralRepresentation {
     threshold: u64,
 }
 
-impl LintPass for LiteralRepresentation {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DECIMAL_LITERAL_REPRESENTATION)
-    }
-}
+impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]);
 
-impl EarlyLintPass for LiteralRepresentation {
+impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if in_external_macro(cx.sess(), expr.span) {
             return;
@@ -432,11 +497,9 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
     }
 }
 
-impl LiteralRepresentation {
+impl DecimalLiteralRepresentation {
     pub fn new(threshold: u64) -> Self {
-        Self {
-            threshold,
-        }
+        Self { threshold }
     }
     fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
         // Lint integral literals.
@@ -445,23 +508,20 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
             if let Some(src) = snippet_opt(cx, lit.span);
             if let Some(firstch) = src.chars().next();
             if char::to_digit(firstch, 10).is_some();
+            let digit_info = DigitInfo::new(&src, false);
+            if digit_info.radix == Radix::Decimal;
+            if let Ok(val) = digit_info.digits
+                .chars()
+                .filter(|&c| c != '_')
+                .collect::<String>()
+                .parse::<u128>();
+            if val >= u128::from(self.threshold);
             then {
-                let digit_info = DigitInfo::new(&src, false);
-                if digit_info.radix == Radix::Decimal {
-                    let val = digit_info.digits
-                        .chars()
-                        .filter(|&c| c != '_')
-                        .collect::<String>()
-                        .parse::<u128>().unwrap();
-                    if val < u128::from(self.threshold) {
-                        return
-                    }
-                    let hex = format!("{:#X}", val);
-                    let digit_info = DigitInfo::new(&hex[..], false);
-                    let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
-                        warning_type.display(&digit_info.grouping_hint(), cx, lit.span)
-                    });
-                }
+                let hex = format!("{:#X}", val);
+                let digit_info = DigitInfo::new(&hex, false);
+                let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
+                    warning_type.display(&digit_info.grouping_hint(), cx, lit.span)
+                });
             }
         }
     }
@@ -469,7 +529,12 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
     fn do_lint(digits: &str) -> Result<(), WarningType> {
         if digits.len() == 1 {
             // Lint for 1 digit literals, if someone really sets the threshold that low
-            if digits == "1" || digits == "2" || digits == "4" || digits == "8" || digits == "3" || digits == "7"
+            if digits == "1"
+                || digits == "2"
+                || digits == "4"
+                || digits == "8"
+                || digits == "3"
+                || digits == "7"
                 || digits == "F"
             {
                 return Err(WarningType::DecimalRepresentation);
@@ -478,6 +543,7 @@ fn do_lint(digits: &str) -> Result<(), WarningType> {
             // Lint for Literals with a hex-representation of 2 or 3 digits
             let f = &digits[0..1]; // first digit
             let s = &digits[1..]; // suffix
+
             // Powers of 2
             if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && s.chars().all(|c| c == '0'))
                 // Powers of 2 minus 1
@@ -490,6 +556,7 @@ fn do_lint(digits: &str) -> Result<(), WarningType> {
             let f = &digits[0..1]; // first digit
             let m = &digits[1..digits.len() - 1]; // middle digits, except last
             let s = &digits[1..]; // suffix
+
             // Powers of 2 with a margin of +15/-16
             if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0'))
                 || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F'))
@@ -504,3 +571,23 @@ fn do_lint(digits: &str) -> Result<(), WarningType> {
         Ok(())
     }
 }
+
+fn is_mistyped_suffix(suffix: &str) -> bool {
+    ["_8", "_16", "_32", "_64"].contains(&suffix)
+}
+
+fn is_possible_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
+    ((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) && is_mistyped_suffix(lit.split_at(idx).1)
+}
+
+fn is_mistyped_float_suffix(suffix: &str) -> bool {
+    ["_32", "_64"].contains(&suffix)
+}
+
+fn is_possible_float_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
+    (len > 3 && idx == len - 3) && is_mistyped_float_suffix(lit.split_at(idx).1)
+}
+
+fn has_possible_float_suffix(lit: &str) -> bool {
+    lit.ends_with("_32") || lit.ends_with("_64")
+}
index db449d7c6a263693d46f393d8f0c38d61d9d27cc..9280461548cf45b290fe549378b6bb72ecac687c 100644 (file)
-use itertools::Itertools;
 use crate::reexport::*;
-use rustc::hir::*;
-use rustc::hir::def::Def;
-use rustc::hir::def_id;
-use rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
-use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
+use itertools::Itertools;
+use rustc::hir::def::{DefKind, Res};
+use rustc::hir::def_id;
+use rustc::hir::intravisit::{walk_block, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::middle::region;
+use rustc::{declare_lint_pass, declare_tool_lint};
 // use rustc::middle::region::CodeExtent;
+use crate::consts::{constant, Constant};
+use crate::utils::sym;
+use crate::utils::usage::mutated_variables;
+use crate::utils::{in_macro_or_desugar, sext, sugg};
 use rustc::middle::expr_use_visitor::*;
-use rustc::middle::mem_categorization::Categorization;
 use rustc::middle::mem_categorization::cmt_;
-use rustc::ty::{self, Ty};
+use rustc::middle::mem_categorization::Categorization;
 use rustc::ty::subst::Subst;
-use std::collections::{HashMap, HashSet};
+use rustc::ty::{self, Ty};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
 use std::iter::{once, Iterator};
+use std::mem;
 use syntax::ast;
-use syntax::codemap::Span;
-use crate::utils::{sugg, sext};
-use crate::utils::usage::mutated_variables;
-use crate::consts::{constant, Constant};
+use syntax::source_map::Span;
+use syntax_pos::BytePos;
 
-use crate::utils::{get_enclosing_block, get_parent_expr, higher, is_integer_literal, is_refutable,
-            last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt,
-            span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, SpanlessEq};
 use crate::utils::paths;
+use crate::utils::{
+    get_enclosing_block, get_parent_expr, has_iter_method, higher, is_integer_literal, is_refutable, last_path_segment,
+    match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt, snippet_with_applicability,
+    span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, SpanlessEq,
+};
 
-/// **What it does:** Checks for for-loops that manually copy items between
-/// slices that could be optimized by having a memcpy.
-///
-/// **Why is this bad?** It is not as fast as a memcpy.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for i in 0..src.len() {
-///     dst[i + 64] = src[i];
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for for-loops that manually copy items between
+    /// slices that could be optimized by having a memcpy.
+    ///
+    /// **Why is this bad?** It is not as fast as a memcpy.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for i in 0..src.len() {
+    ///     dst[i + 64] = src[i];
+    /// }
+    /// ```
     pub MANUAL_MEMCPY,
     perf,
     "manually copying items between slices"
 }
 
-/// **What it does:** Checks for looping over the range of `0..len` of some
-/// collection just to get the values by index.
-///
-/// **Why is this bad?** Just iterating the collection itself makes the intent
-/// more clear and is probably faster.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for i in 0..vec.len() {
-///     println!("{}", vec[i]);
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for looping over the range of `0..len` of some
+    /// collection just to get the values by index.
+    ///
+    /// **Why is this bad?** Just iterating the collection itself makes the intent
+    /// more clear and is probably faster.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for i in 0..vec.len() {
+    ///     println!("{}", vec[i]);
+    /// }
+    /// ```
     pub NEEDLESS_RANGE_LOOP,
     style,
     "for-looping over a range of indices where an iterator over items would do"
 }
 
-/// **What it does:** Checks for loops on `x.iter()` where `&x` will do, and
-/// suggests the latter.
-///
-/// **Why is this bad?** Readability.
-///
-/// **Known problems:** False negatives. We currently only warn on some known
-/// types.
-///
-/// **Example:**
-/// ```rust
-/// // with `y` a `Vec` or slice:
-/// for x in y.iter() { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for loops on `x.iter()` where `&x` will do, and
+    /// suggests the latter.
+    ///
+    /// **Why is this bad?** Readability.
+    ///
+    /// **Known problems:** False negatives. We currently only warn on some known
+    /// types.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// // with `y` a `Vec` or slice:
+    /// for x in y.iter() {
+    ///     ..
+    /// }
+    /// ```
+    /// can be rewritten to
+    /// ```rust
+    /// for x in &y {
+    ///     ..
+    /// }
+    /// ```
     pub EXPLICIT_ITER_LOOP,
-    style,
+    pedantic,
     "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do"
 }
 
-/// **What it does:** Checks for loops on `y.into_iter()` where `y` will do, and
-/// suggests the latter.
-///
-/// **Why is this bad?** Readability.
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// // with `y` a `Vec` or slice:
-/// for x in y.into_iter() { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for loops on `y.into_iter()` where `y` will do, and
+    /// suggests the latter.
+    ///
+    /// **Why is this bad?** Readability.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// // with `y` a `Vec` or slice:
+    /// for x in y.into_iter() {
+    ///     ..
+    /// }
+    /// ```
+    /// can be rewritten to
+    /// ```ignore
+    /// for x in y {
+    ///     ..
+    /// }
+    /// ```
     pub EXPLICIT_INTO_ITER_LOOP,
-    style,
+    pedantic,
     "for-looping over `_.into_iter()` when `_` would do"
 }
 
-/// **What it does:** Checks for loops on `x.next()`.
-///
-/// **Why is this bad?** `next()` returns either `Some(value)` if there was a
-/// value, or `None` otherwise. The insidious thing is that `Option<_>`
-/// implements `IntoIterator`, so that possibly one value will be iterated,
-/// leading to some hard to find bugs. No one will want to write such code
-/// [except to win an Underhanded Rust
-/// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for x in y.next() { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for loops on `x.next()`.
+    ///
+    /// **Why is this bad?** `next()` returns either `Some(value)` if there was a
+    /// value, or `None` otherwise. The insidious thing is that `Option<_>`
+    /// implements `IntoIterator`, so that possibly one value will be iterated,
+    /// leading to some hard to find bugs. No one will want to write such code
+    /// [except to win an Underhanded Rust
+    /// Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for x in y.next() {
+    ///     ..
+    /// }
+    /// ```
     pub ITER_NEXT_LOOP,
     correctness,
     "for-looping over `_.next()` which is probably not intended"
 }
 
-/// **What it does:** Checks for `for` loops over `Option` values.
-///
-/// **Why is this bad?** Readability. This is more clearly expressed as an `if
-/// let`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for x in option { .. }
-/// ```
-///
-/// This should be
-/// ```rust
-/// if let Some(x) = option { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `for` loops over `Option` values.
+    ///
+    /// **Why is this bad?** Readability. This is more clearly expressed as an `if
+    /// let`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for x in option {
+    ///     ..
+    /// }
+    /// ```
+    ///
+    /// This should be
+    /// ```ignore
+    /// if let Some(x) = option {
+    ///     ..
+    /// }
+    /// ```
     pub FOR_LOOP_OVER_OPTION,
     correctness,
     "for-looping over an `Option`, which is more clearly expressed as an `if let`"
 }
 
-/// **What it does:** Checks for `for` loops over `Result` values.
-///
-/// **Why is this bad?** Readability. This is more clearly expressed as an `if
-/// let`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for x in result { .. }
-/// ```
-///
-/// This should be
-/// ```rust
-/// if let Ok(x) = result { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `for` loops over `Result` values.
+    ///
+    /// **Why is this bad?** Readability. This is more clearly expressed as an `if
+    /// let`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for x in result {
+    ///     ..
+    /// }
+    /// ```
+    ///
+    /// This should be
+    /// ```ignore
+    /// if let Ok(x) = result {
+    ///     ..
+    /// }
+    /// ```
     pub FOR_LOOP_OVER_RESULT,
     correctness,
     "for-looping over a `Result`, which is more clearly expressed as an `if let`"
 }
 
-/// **What it does:** Detects `loop + match` combinations that are easier
-/// written as a `while let` loop.
-///
-/// **Why is this bad?** The `while let` loop is usually shorter and more
-/// readable.
-///
-/// **Known problems:** Sometimes the wrong binding is displayed (#383).
-///
-/// **Example:**
-/// ```rust
-/// loop {
-///     let x = match y {
-///         Some(x) => x,
-///         None => break,
-///     }
-///     // .. do something with x
-/// }
-/// // is easier written as
-/// while let Some(x) = y {
-///     // .. do something with x
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects `loop + match` combinations that are easier
+    /// written as a `while let` loop.
+    ///
+    /// **Why is this bad?** The `while let` loop is usually shorter and more
+    /// readable.
+    ///
+    /// **Known problems:** Sometimes the wrong binding is displayed (#383).
+    ///
+    /// **Example:**
+    /// ```rust
+    /// loop {
+    ///     let x = match y {
+    ///         Some(x) => x,
+    ///         None => break,
+    ///     }
+    ///     // .. do something with x
+    /// }
+    /// // is easier written as
+    /// while let Some(x) = y {
+    ///     // .. do something with x
+    /// }
+    /// ```
     pub WHILE_LET_LOOP,
     complexity,
     "`loop { if let { ... } else break }`, which can be written as a `while let` loop"
 }
 
-/// **What it does:** Checks for using `collect()` on an iterator without using
-/// the result.
-///
-/// **Why is this bad?** It is more idiomatic to use a `for` loop over the
-/// iterator instead.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for using `collect()` on an iterator without using
+    /// the result.
+    ///
+    /// **Why is this bad?** It is more idiomatic to use a `for` loop over the
+    /// iterator instead.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// vec.iter().map(|x| /* some operation returning () */).collect::<Vec<_>>();
+    /// ```
     pub UNUSED_COLLECT,
     perf,
-    "`collect()`ing an iterator without using the result; this is usually better \
-     written as a for loop"
-}
-
-/// **What it does:** Checks for loops over ranges `x..y` where both `x` and `y`
-/// are constant and `x` is greater or equal to `y`, unless the range is
-/// reversed or has a negative `.step_by(_)`.
-///
-/// **Why is it bad?** Such loops will either be skipped or loop until
-/// wrap-around (in debug code, this may `panic!()`). Both options are probably
-/// not intended.
-///
-/// **Known problems:** The lint cannot catch loops over dynamically defined
-/// ranges. Doing this would require simulating all possible inputs and code
-/// paths through the program, which would be complex and error-prone.
-///
-/// **Example:**
-/// ```rust
-/// for x in 5..10-5 { .. } // oops, stray `-`
-/// ```
+    "`collect()`ing an iterator without using the result; this is usually better written as a for loop"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for functions collecting an iterator when collect
+    /// is not needed.
+    ///
+    /// **Why is this bad?** `collect` causes the allocation of a new data structure,
+    /// when this allocation may not be needed.
+    ///
+    /// **Known problems:**
+    /// None
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let len = iterator.collect::<Vec<_>>().len();
+    /// // should be
+    /// let len = iterator.count();
+    /// ```
+    pub NEEDLESS_COLLECT,
+    perf,
+    "collecting an iterator when collect is not needed"
+}
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for loops over ranges `x..y` where both `x` and `y`
+    /// are constant and `x` is greater or equal to `y`, unless the range is
+    /// reversed or has a negative `.step_by(_)`.
+    ///
+    /// **Why is it bad?** Such loops will either be skipped or loop until
+    /// wrap-around (in debug code, this may `panic!()`). Both options are probably
+    /// not intended.
+    ///
+    /// **Known problems:** The lint cannot catch loops over dynamically defined
+    /// ranges. Doing this would require simulating all possible inputs and code
+    /// paths through the program, which would be complex and error-prone.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for x in 5..10 - 5 {
+    ///     ..
+    /// } // oops, stray `-`
+    /// ```
     pub REVERSE_RANGE_LOOP,
     correctness,
     "iteration over an empty range, such as `10..0` or `5..5`"
 }
 
-/// **What it does:** Checks `for` loops over slices with an explicit counter
-/// and suggests the use of `.enumerate()`.
-///
-/// **Why is it bad?** Not only is the version using `.enumerate()` more
-/// readable, the compiler is able to remove bounds checks which can lead to
-/// faster code in some instances.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for i in 0..v.len() { foo(v[i]);
-/// for i in 0..v.len() { bar(i, v[i]); }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks `for` loops over slices with an explicit counter
+    /// and suggests the use of `.enumerate()`.
+    ///
+    /// **Why is it bad?** Not only is the version using `.enumerate()` more
+    /// readable, the compiler is able to remove bounds checks which can lead to
+    /// faster code in some instances.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for i in 0..v.len() { foo(v[i]);
+    /// for i in 0..v.len() { bar(i, v[i]); }
+    /// ```
     pub EXPLICIT_COUNTER_LOOP,
     complexity,
     "for-looping with an explicit counter when `_.enumerate()` would do"
 }
 
-/// **What it does:** Checks for empty `loop` expressions.
-///
-/// **Why is this bad?** Those busy loops burn CPU cycles without doing
-/// anything. Think of the environment and either block on something or at least
-/// make the thread sleep for some microseconds.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// loop {}
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for empty `loop` expressions.
+    ///
+    /// **Why is this bad?** Those busy loops burn CPU cycles without doing
+    /// anything. Think of the environment and either block on something or at least
+    /// make the thread sleep for some microseconds.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```no_run
+    /// loop {}
+    /// ```
     pub EMPTY_LOOP,
     style,
     "empty `loop {}`, which should block or sleep"
 }
 
-/// **What it does:** Checks for `while let` expressions on iterators.
-///
-/// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys
-/// the intent better.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// while let Some(val) = iter() { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `while let` expressions on iterators.
+    ///
+    /// **Why is this bad?** Readability. A simple `for` loop is shorter and conveys
+    /// the intent better.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// while let Some(val) = iter() {
+    ///     ..
+    /// }
+    /// ```
     pub WHILE_LET_ON_ITERATOR,
     style,
     "using a while-let loop instead of a for loop on an iterator"
 }
 
-/// **What it does:** Checks for iterating a map (`HashMap` or `BTreeMap`) and
-/// ignoring either the keys or values.
-///
-/// **Why is this bad?** Readability. There are `keys` and `values` methods that
-/// can be used to express that don't need the values or keys.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for (k, _) in &map { .. }
-/// ```
-///
-/// could be replaced by
-///
-/// ```rust
-/// for k in map.keys() { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for iterating a map (`HashMap` or `BTreeMap`) and
+    /// ignoring either the keys or values.
+    ///
+    /// **Why is this bad?** Readability. There are `keys` and `values` methods that
+    /// can be used to express that don't need the values or keys.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for (k, _) in &map {
+    ///     ..
+    /// }
+    /// ```
+    ///
+    /// could be replaced by
+    ///
+    /// ```ignore
+    /// for k in map.keys() {
+    ///     ..
+    /// }
+    /// ```
     pub FOR_KV_MAP,
     style,
     "looping on a map using `iter` when `keys` or `values` would do"
 }
 
-/// **What it does:** Checks for loops that will always `break`, `return` or
-/// `continue` an outer loop.
-///
-/// **Why is this bad?** This loop never loops, all it does is obfuscating the
-/// code.
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// loop { ..; break; }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for loops that will always `break`, `return` or
+    /// `continue` an outer loop.
+    ///
+    /// **Why is this bad?** This loop never loops, all it does is obfuscating the
+    /// code.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// loop {
+    ///     ..;
+    ///     break;
+    /// }
+    /// ```
     pub NEVER_LOOP,
     correctness,
     "any loop that will always `break` or `return`"
 }
 
-/// **What it does:** Checks for loops which have a range bound that is a mutable variable
-///
-/// **Why is this bad?** One might think that modifying the mutable variable changes the loop bounds
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// let mut foo = 42;
-/// for i in 0..foo {
-///     foo -= 1;
-///     println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for loops which have a range bound that is a mutable variable
+    ///
+    /// **Why is this bad?** One might think that modifying the mutable variable changes the loop bounds
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut foo = 42;
+    /// for i in 0..foo {
+    ///     foo -= 1;
+    ///     println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
+    /// }
+    /// ```
     pub MUT_RANGE_BOUND,
     complexity,
     "for loop over a range where one of the bounds is a mutable variable"
 }
 
-/// **What it does:** Checks whether variables used within while loop condition
-/// can be (and are) mutated in the body.
-///
-/// **Why is this bad?** If the condition is unchanged, entering the body of the loop
-/// will lead to an infinite loop.
-///
-/// **Known problems:** If the `while`-loop is in a closure, the check for mutation of the
-/// condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
-/// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
-///
-/// **Example:**
-/// ```rust
-/// let i = 0;
-/// while i > 10 {
-///    println!("let me loop forever!");
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks whether variables used within while loop condition
+    /// can be (and are) mutated in the body.
+    ///
+    /// **Why is this bad?** If the condition is unchanged, entering the body of the loop
+    /// will lead to an infinite loop.
+    ///
+    /// **Known problems:** If the `while`-loop is in a closure, the check for mutation of the
+    /// condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
+    /// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let i = 0;
+    /// while i > 10 {
+    ///     println!("let me loop forever!");
+    /// }
+    /// ```
     pub WHILE_IMMUTABLE_CONDITION,
     correctness,
     "variables used within while expression are not mutated in the body"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            MANUAL_MEMCPY,
-            NEEDLESS_RANGE_LOOP,
-            EXPLICIT_ITER_LOOP,
-            EXPLICIT_INTO_ITER_LOOP,
-            ITER_NEXT_LOOP,
-            FOR_LOOP_OVER_RESULT,
-            FOR_LOOP_OVER_OPTION,
-            WHILE_LET_LOOP,
-            UNUSED_COLLECT,
-            REVERSE_RANGE_LOOP,
-            EXPLICIT_COUNTER_LOOP,
-            EMPTY_LOOP,
-            WHILE_LET_ON_ITERATOR,
-            FOR_KV_MAP,
-            NEVER_LOOP,
-            MUT_RANGE_BOUND,
-            WHILE_IMMUTABLE_CONDITION,
-        )
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+declare_lint_pass!(Loops => [
+    MANUAL_MEMCPY,
+    NEEDLESS_RANGE_LOOP,
+    EXPLICIT_ITER_LOOP,
+    EXPLICIT_INTO_ITER_LOOP,
+    ITER_NEXT_LOOP,
+    FOR_LOOP_OVER_RESULT,
+    FOR_LOOP_OVER_OPTION,
+    WHILE_LET_LOOP,
+    UNUSED_COLLECT,
+    NEEDLESS_COLLECT,
+    REVERSE_RANGE_LOOP,
+    EXPLICIT_COUNTER_LOOP,
+    EMPTY_LOOP,
+    WHILE_LET_ON_ITERATOR,
+    FOR_KV_MAP,
+    NEVER_LOOP,
+    MUT_RANGE_BOUND,
+    WHILE_IMMUTABLE_CONDITION,
+]);
+
+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) {
+            return;
+        }
+
         if let Some((pat, arg, body)) = higher::for_loop(expr) {
             check_for_loop(cx, pat, arg, body, expr);
         }
@@ -414,9 +476,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         // check for never_loop
         match expr.node {
             ExprKind::While(_, ref block, _) | ExprKind::Loop(ref block, _, _) => {
-                match never_loop_block(block, expr.id) {
-                    NeverLoopResult::AlwaysBreak =>
-                        span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
+                match never_loop_block(block, expr.hir_id) {
+                    NeverLoopResult::AlwaysBreak => {
+                        span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops")
+                    },
                     NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
                 }
             },
@@ -446,19 +509,23 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     // ensure "if let" compatible match structure
                     match *source {
                         MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
-                            if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none()
-                                && arms[1].pats.len() == 1 && arms[1].guard.is_none()
+                            if arms.len() == 2
+                                && arms[0].pats.len() == 1
+                                && arms[0].guard.is_none()
+                                && arms[1].pats.len() == 1
+                                && arms[1].guard.is_none()
                                 && is_simple_break_expr(&arms[1].body)
                             {
                                 if in_external_macro(cx.sess(), expr.span) {
                                     return;
                                 }
 
-                                // NOTE: we used to make build a body here instead of using
+                                // NOTE: we used to build a body here instead of using
                                 // ellipsis, this was removed because:
                                 // 1) it was ugly with big bodies;
                                 // 2) it was not indented properly;
                                 // 3) it wasn’t very smart (see #675).
+                                let mut applicability = Applicability::HasPlaceholders;
                                 span_lint_and_sugg(
                                     cx,
                                     WHILE_LET_LOOP,
@@ -467,9 +534,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                                     "try",
                                     format!(
                                         "while let {} = {} {{ .. }}",
-                                        snippet(cx, arms[0].pats[0].span, ".."),
-                                        snippet(cx, matchexpr.span, "..")
+                                        snippet_with_applicability(cx, arms[0].pats[0].span, "..", &mut applicability),
+                                        snippet_with_applicability(cx, matchexpr.span, "..", &mut applicability),
                                     ),
+                                    applicability,
                                 );
                             }
                         },
@@ -487,12 +555,14 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             {
                 let iter_expr = &method_args[0];
                 let lhs_constructor = last_path_segment(qpath);
-                if method_path.ident.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR)
-                    && lhs_constructor.ident.name == "Some" && (
-                        pat_args.is_empty()
+                if method_path.ident.name == *sym::next
+                    && match_trait_method(cx, match_expr, &*paths::ITERATOR)
+                    && lhs_constructor.ident.name == *sym::Some
+                    && (pat_args.is_empty()
                         || !is_refutable(cx, &pat_args[0])
-                        && !is_iterator_used_after_while_let(cx, iter_expr)
-                        && !is_nested(cx, expr, &method_args[0]))
+                            && !is_used_inside(cx, iter_expr, &arms[0].body)
+                            && !is_iterator_used_after_while_let(cx, iter_expr)
+                            && !is_nested(cx, expr, &method_args[0]))
                 {
                     let iterator = snippet(cx, method_args[0].span, "_");
                     let loop_var = if pat_args.is_empty() {
@@ -507,6 +577,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                         "this loop could be written as a `for` loop",
                         "try",
                         format!("for {} in {} {{ .. }}", loop_var, iterator),
+                        Applicability::HasPlaceholders,
                     );
                 }
             }
@@ -516,12 +587,17 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::While(ref cond, _, _) = expr.node {
             check_infinite_loop(cx, cond, expr);
         }
+
+        check_needless_collect(expr, cx);
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
-        if let StmtKind::Semi(ref expr, _) = stmt.node {
+        if let StmtKind::Semi(ref expr) = stmt.node {
             if let ExprKind::MethodCall(ref method, _, ref args) = expr.node {
-                if args.len() == 1 && method.ident.name == "collect" && match_trait_method(cx, expr, &paths::ITERATOR) {
+                if args.len() == 1
+                    && method.ident.name == *sym::collect
+                    && match_trait_method(cx, expr, &*paths::ITERATOR)
+                {
                     span_lint(
                         cx,
                         UNUSED_COLLECT,
@@ -545,8 +621,7 @@ enum NeverLoopResult {
 
 fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
     match *arg {
-        NeverLoopResult::AlwaysBreak |
-        NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
+        NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
         NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
     }
 }
@@ -562,28 +637,26 @@ fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResu
 // Combine two results where both parts are called but not necessarily in order.
 fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
     match (left, right) {
-        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) =>
-            NeverLoopResult::MayContinueMainLoop,
-        (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) =>
-            NeverLoopResult::AlwaysBreak,
-        (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) =>
-            NeverLoopResult::Otherwise,
+        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
+            NeverLoopResult::MayContinueMainLoop
+        },
+        (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
+        (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
     }
 }
 
 // Combine two results where only one of the part may have been executed.
 fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
     match (b1, b2) {
-        (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) =>
-            NeverLoopResult::AlwaysBreak,
-        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) =>
-            NeverLoopResult::MayContinueMainLoop,
-        (NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) =>
-            NeverLoopResult::Otherwise,
+        (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
+        (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
+            NeverLoopResult::MayContinueMainLoop
+        },
+        (NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
     }
 }
 
-fn never_loop_block(block: &Block, main_loop_id: NodeId) -> NeverLoopResult {
+fn never_loop_block(block: &Block, main_loop_id: HirId) -> NeverLoopResult {
     let stmts = block.stmts.iter().map(stmt_to_expr);
     let expr = once(block.expr.as_ref().map(|p| &**p));
     let mut iter = stmts.chain(expr).filter_map(|e| e);
@@ -593,41 +666,30 @@ fn never_loop_block(block: &Block, main_loop_id: NodeId) -> NeverLoopResult {
 fn stmt_to_expr(stmt: &Stmt) -> Option<&Expr> {
     match stmt.node {
         StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e),
-        StmtKind::Decl(ref d, ..) => decl_to_expr(d),
-    }
-}
-
-fn decl_to_expr(decl: &Decl) -> Option<&Expr> {
-    match decl.node {
-        DeclKind::Local(ref local) => local.init.as_ref().map(|p| &**p),
+        StmtKind::Local(ref local) => local.init.as_ref().map(|p| &**p),
         _ => None,
     }
 }
 
-fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
+fn never_loop_expr(expr: &Expr, main_loop_id: HirId) -> NeverLoopResult {
     match expr.node {
-        ExprKind::Box(ref e) |
-        ExprKind::Unary(_, ref e) |
-        ExprKind::Cast(ref e, _) |
-        ExprKind::Type(ref e, _) |
-        ExprKind::Field(ref e, _) |
-        ExprKind::AddrOf(_, ref e) |
-        ExprKind::Struct(_, _, Some(ref e)) |
-        ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id),
+        ExprKind::Box(ref e)
+        | ExprKind::Unary(_, ref e)
+        | ExprKind::Cast(ref e, _)
+        | ExprKind::Type(ref e, _)
+        | ExprKind::Field(ref e, _)
+        | ExprKind::AddrOf(_, ref e)
+        | ExprKind::Struct(_, _, Some(ref e))
+        | ExprKind::Repeat(ref e, _)
+        | ExprKind::DropTemps(ref e) => never_loop_expr(e, main_loop_id),
         ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es) | ExprKind::Tup(ref es) => {
             never_loop_expr_all(&mut es.iter(), main_loop_id)
         },
         ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
-        ExprKind::Binary(_, ref e1, ref e2) |
-        ExprKind::Assign(ref e1, ref e2) |
-        ExprKind::AssignOp(_, ref e1, ref e2) |
-        ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
-        ExprKind::If(ref e, ref e2, ref e3) => {
-            let e1 = never_loop_expr(e, main_loop_id);
-            let e2 = never_loop_expr(e2, main_loop_id);
-            let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
-            combine_seq(e1, combine_branches(e2, e3))
-        },
+        ExprKind::Binary(_, ref e1, ref e2)
+        | ExprKind::Assign(ref e1, ref e2)
+        | ExprKind::AssignOp(_, ref e1, ref e2)
+        | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
         ExprKind::Loop(ref b, _, _) => {
             // Break can come from the inner loop so remove them.
             absorb_break(&never_loop_block(b, main_loop_id))
@@ -649,17 +711,16 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
         },
         ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id),
         ExprKind::Continue(d) => {
-            let id = d.target_id
-                .expect("target id can only be missing in the presence of compilation errors");
+            let id = d
+                .target_id
+                .expect("target ID can only be missing in the presence of compilation errors");
             if id == main_loop_id {
                 NeverLoopResult::MayContinueMainLoop
             } else {
                 NeverLoopResult::AlwaysBreak
             }
         },
-        ExprKind::Break(_, _) => {
-            NeverLoopResult::AlwaysBreak
-        },
+        ExprKind::Break(_, _) => NeverLoopResult::AlwaysBreak,
         ExprKind::Ret(ref e) => {
             if let Some(ref e) = *e {
                 combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
@@ -667,26 +728,27 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
                 NeverLoopResult::AlwaysBreak
             }
         },
-        ExprKind::Struct(_, _, None) |
-        ExprKind::Yield(_) |
-        ExprKind::Closure(_, _, _, _, _) |
-        ExprKind::InlineAsm(_, _, _) |
-        ExprKind::Path(_) |
-        ExprKind::Lit(_) => NeverLoopResult::Otherwise,
+        ExprKind::Struct(_, _, None)
+        | ExprKind::Yield(_)
+        | ExprKind::Closure(_, _, _, _, _)
+        | ExprKind::InlineAsm(_, _, _)
+        | ExprKind::Path(_)
+        | ExprKind::Lit(_)
+        | ExprKind::Err => NeverLoopResult::Otherwise,
     }
 }
 
-fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
+fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
     es.map(|e| never_loop_expr(e, main_loop_id))
         .fold(NeverLoopResult::Otherwise, combine_seq)
 }
 
-fn never_loop_expr_all<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
+fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, main_loop_id: HirId) -> NeverLoopResult {
     es.map(|e| never_loop_expr(e, main_loop_id))
         .fold(NeverLoopResult::Otherwise, combine_both)
 }
 
-fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
+fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr>>(e: &mut T, main_loop_id: HirId) -> NeverLoopResult {
     e.map(|e| never_loop_expr(e, main_loop_id))
         .fold(NeverLoopResult::AlwaysBreak, combine_branches)
 }
@@ -701,18 +763,18 @@ fn check_for_loop<'a, 'tcx>(
     check_for_loop_range(cx, pat, arg, body, expr);
     check_for_loop_reverse_range(cx, arg, expr);
     check_for_loop_arg(cx, pat, arg, expr);
-    check_for_loop_explicit_counter(cx, arg, body, expr);
+    check_for_loop_explicit_counter(cx, pat, arg, body, expr);
     check_for_loop_over_map_kv(cx, pat, arg, body, expr);
     check_for_mut_range_bound(cx, arg, body);
     detect_manual_memcpy(cx, pat, arg, body, expr);
 }
 
-fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> bool {
+fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: HirId) -> bool {
     if_chain! {
         if let ExprKind::Path(ref qpath) = expr.node;
         if let QPath::Resolved(None, ref path) = *qpath;
         if path.segments.len() == 1;
-        if let Def::Local(local_id) = cx.tables.qpath_def(qpath, expr.hir_id);
+        if let Res::Local(local_id) = cx.tables.qpath_res(qpath, expr.hir_id);
         // our variable!
         if local_id == var;
         then {
@@ -730,10 +792,7 @@ struct Offset {
 
 impl Offset {
     fn negative(s: String) -> Self {
-        Self {
-            value: s,
-            negate: true,
-        }
+        Self { value: s, negate: true }
     }
 
     fn positive(s: String) -> Self {
@@ -751,16 +810,16 @@ struct FixedOffsetVar {
 
 fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool {
     let is_slice = match ty.sty {
-        ty::TyRef(_, subty, _) => is_slice_like(cx, subty),
-        ty::TySlice(..) | ty::TyArray(..) => true,
+        ty::Ref(_, subty, _) => is_slice_like(cx, subty),
+        ty::Slice(..) | ty::Array(..) => true,
         _ => false,
     };
 
-    is_slice || match_type(cx, ty, &paths::VEC) || match_type(cx, ty, &paths::VEC_DEQUE)
+    is_slice || match_type(cx, ty, &*paths::VEC) || match_type(cx, ty, &*paths::VEC_DEQUE)
 }
 
-fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> Option<FixedOffsetVar> {
-    fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::NodeId) -> Option<String> {
+fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: HirId) -> Option<FixedOffsetVar> {
+    fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: HirId) -> Option<String> {
         match e.node {
             ExprKind::Lit(ref l) => match l.node {
                 ast::LitKind::Int(x, _ty) => Some(x.to_string()),
@@ -793,19 +852,19 @@ fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::Node
                 BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
                 _ => None,
             },
-            ExprKind::Path(..) => if same_var(cx, idx, var) {
-                Some(Offset::positive("0".into()))
-            } else {
-                None
+            ExprKind::Path(..) => {
+                if same_var(cx, idx, var) {
+                    Some(Offset::positive("0".into()))
+                } else {
+                    None
+                }
             },
             _ => None,
         };
 
-        offset.map(|o| {
-            FixedOffsetVar {
-                var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
-                offset: o,
-            }
+        offset.map(|o| FixedOffsetVar {
+            var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
+            offset: o,
         })
     } else {
         None
@@ -815,11 +874,11 @@ fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr, var: ast::Node
 fn fetch_cloned_fixed_offset_var<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     expr: &Expr,
-    var: ast::NodeId,
+    var: HirId,
 ) -> Option<FixedOffsetVar> {
     if_chain! {
         if let ExprKind::MethodCall(ref method, _, ref args) = expr.node;
-        if method.ident.name == "clone";
+        if method.ident.name == *sym::clone;
         if args.len() == 1;
         if let Some(arg) = args.get(0);
         then {
@@ -833,15 +892,18 @@ fn fetch_cloned_fixed_offset_var<'a, 'tcx>(
 fn get_indexed_assignments<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     body: &Expr,
-    var: ast::NodeId,
+    var: HirId,
 ) -> Vec<(FixedOffsetVar, FixedOffsetVar)> {
     fn get_assignment<'a, 'tcx>(
         cx: &LateContext<'a, 'tcx>,
         e: &Expr,
-        var: ast::NodeId,
+        var: HirId,
     ) -> Option<(FixedOffsetVar, FixedOffsetVar)> {
         if let ExprKind::Assign(ref lhs, ref rhs) = e.node {
-            match (get_fixed_offset_var(cx, lhs, var), fetch_cloned_fixed_offset_var(cx, rhs, var)) {
+            match (
+                get_fixed_offset_var(cx, lhs, var),
+                fetch_cloned_fixed_offset_var(cx, rhs, var),
+            ) {
                 (Some(offset_left), Some(offset_right)) => {
                     // Source and destination must be different
                     if offset_left.var_name == offset_right.var_name {
@@ -859,22 +921,16 @@ fn get_assignment<'a, 'tcx>(
 
     if let ExprKind::Block(ref b, _) = body.node {
         let Block {
-            ref stmts,
-            ref expr,
-            ..
+            ref stmts, ref expr, ..
         } = **b;
 
         stmts
             .iter()
             .map(|stmt| match stmt.node {
-                StmtKind::Decl(..) => None,
-                StmtKind::Expr(ref e, _node_id) | StmtKind::Semi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
+                StmtKind::Local(..) | StmtKind::Item(..) => None,
+                StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => Some(get_assignment(cx, e, var)),
             })
-            .chain(
-                expr.as_ref()
-                    .into_iter()
-                    .map(|e| Some(get_assignment(cx, &*e, var))),
-            )
+            .chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var))))
             .filter_map(|op| op)
             .collect::<Option<Vec<_>>>()
             .unwrap_or_else(|| vec![])
@@ -883,7 +939,7 @@ fn get_assignment<'a, 'tcx>(
     }
 }
 
-/// Check for for loops that sequentially copy items from one slice-like
+/// Checks for for loops that sequentially copy items from one slice-like
 /// object to another.
 fn detect_manual_memcpy<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
@@ -906,39 +962,53 @@ fn detect_manual_memcpy<'a, 'tcx>(
                     ("0", _, x, false) | (x, false, "0", false) => x.into(),
                     ("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
                     (x, false, y, false) => format!("({} + {})", x, y),
-                    (x, false, y, true) => format!("({} - {})", x, y),
-                    (x, true, y, false) => format!("({} - {})", y, x),
+                    (x, false, y, true) => {
+                        if x == y {
+                            "0".into()
+                        } else {
+                            format!("({} - {})", x, y)
+                        }
+                    },
+                    (x, true, y, false) => {
+                        if x == y {
+                            "0".into()
+                        } else {
+                            format!("({} - {})", y, x)
+                        }
+                    },
                     (x, true, y, true) => format!("-({} + {})", x, y),
                 }
             };
 
-            let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| if let Some(end) = *end {
-                if_chain! {
-                    if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
-                    if method.ident.name == "len";
-                    if len_args.len() == 1;
-                    if let Some(arg) = len_args.get(0);
-                    if snippet(cx, arg.span, "??") == var_name;
-                    then {
-                        return if offset.negate {
-                            format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
-                        } else {
-                            "".to_owned()
-                        };
+            let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| {
+                if let Some(end) = *end {
+                    if_chain! {
+                        if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
+                        if method.ident.name == *sym::len;
+                        if len_args.len() == 1;
+                        if let Some(arg) = len_args.get(0);
+                        if snippet(cx, arg.span, "??") == var_name;
+                        then {
+                            return if offset.negate {
+                                format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
+                            } else {
+                                String::new()
+                            };
+                        }
                     }
-                }
 
-                let end_str = match limits {
-                    ast::RangeLimits::Closed => {
-                        let end = sugg::Sugg::hir(cx, end, "<count>");
-                        format!("{}", end + sugg::ONE)
-                    },
-                    ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
-                };
+                    let end_str = match limits {
+                        ast::RangeLimits::Closed => {
+                            let end = sugg::Sugg::hir(cx, end, "<count>");
+                            format!("{}", end + sugg::ONE)
+                        },
+                        ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
+                    };
 
-                print_sum(&Offset::positive(end_str), &offset)
-            } else {
-                "..".into()
+                    print_sum(&Offset::positive(end_str), &offset)
+                } else {
+                    "..".into()
+                }
             };
 
             // The only statements in the for loops can be indexed assignments from
@@ -948,7 +1018,7 @@ fn detect_manual_memcpy<'a, 'tcx>(
             let big_sugg = manual_copies
                 .into_iter()
                 .map(|(dst_var, src_var)| {
-                    let start_str = Offset::positive(snippet_opt(cx, start.span).unwrap_or_else(|| "".into()));
+                    let start_str = Offset::positive(snippet(cx, start.span, "").to_string());
                     let dst_offset = print_sum(&start_str, &dst_var.offset);
                     let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name);
                     let src_offset = print_sum(&start_str, &src_var.offset);
@@ -959,7 +1029,10 @@ fn detect_manual_memcpy<'a, 'tcx>(
                         format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit)
                     };
 
-                    format!("{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit)
+                    format!(
+                        "{}.clone_from_slice(&{}[{}..{}])",
+                        dst, src_var.var_name, src_offset, src_limit
+                    )
                 })
                 .join("\n    ");
 
@@ -971,14 +1044,16 @@ fn detect_manual_memcpy<'a, 'tcx>(
                     "it looks like you're manually copying between slices",
                     "try replacing the loop by",
                     big_sugg,
+                    Applicability::Unspecified,
                 );
             }
         }
     }
 }
 
-/// Check for looping over a range and then indexing a sequence with it.
+/// Checks for looping over a range and then indexing a sequence with it.
 /// The iteratee must be a range literal.
+#[allow(clippy::too_many_lines)]
 fn check_for_loop_range<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     pat: &'tcx Pat,
@@ -986,6 +1061,10 @@ fn check_for_loop_range<'a, 'tcx>(
     body: &'tcx Expr,
     expr: &'tcx Expr,
 ) {
+    if in_macro_or_desugar(expr.span) {
+        return;
+    }
+
     if let Some(higher::Range {
         start: Some(start),
         ref end,
@@ -997,10 +1076,10 @@ fn check_for_loop_range<'a, 'tcx>(
             let mut visitor = VarVisitor {
                 cx,
                 var: canonical_id,
-                indexed_mut: HashSet::new(),
-                indexed_indirectly: HashMap::new(),
-                indexed_directly: HashMap::new(),
-                referenced: HashSet::new(),
+                indexed_mut: FxHashSet::default(),
+                indexed_indirectly: FxHashMap::default(),
+                indexed_directly: FxHashMap::default(),
+                referenced: FxHashSet::default(),
                 nonindex: false,
                 prefer_mutable: false,
             };
@@ -1008,7 +1087,7 @@ fn check_for_loop_range<'a, 'tcx>(
 
             // linting condition: we only indexed one variable, and indexed it directly
             if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 {
-                let (indexed, indexed_extent) = visitor
+                let (indexed, (indexed_extent, indexed_ty)) = visitor
                     .indexed_directly
                     .into_iter()
                     .next()
@@ -1016,8 +1095,8 @@ fn check_for_loop_range<'a, 'tcx>(
 
                 // ensure that the indexed variable was declared before the loop, see #601
                 if let Some(indexed_extent) = indexed_extent {
-                    let parent_id = cx.tcx.hir.get_parent(expr.id);
-                    let parent_def_id = cx.tcx.hir.local_def_id(parent_id);
+                    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
+                    let parent_def_id = cx.tcx.hir().local_def_id_from_hir_id(parent_id);
                     let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
                     let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id);
                     if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
@@ -1025,6 +1104,12 @@ fn check_for_loop_range<'a, 'tcx>(
                     }
                 }
 
+                // don't lint if the container that is indexed does not have .iter() method
+                let has_iter = has_iter_method(cx, indexed_ty);
+                if has_iter.is_none() {
+                    return;
+                }
+
                 // don't lint if the container that is indexed into is also used without
                 // indexing
                 if visitor.referenced.contains(&indexed) {
@@ -1034,25 +1119,44 @@ fn check_for_loop_range<'a, 'tcx>(
                 let starts_at_zero = is_integer_literal(start, 0);
 
                 let skip = if starts_at_zero {
-                    "".to_owned()
+                    String::new()
                 } else {
                     format!(".skip({})", snippet(cx, start.span, ".."))
                 };
 
+                let mut end_is_start_plus_val = false;
+
                 let take = if let Some(end) = *end {
-                    if is_len_call(end, indexed) {
-                        "".to_owned()
+                    let mut take_expr = end;
+
+                    if let ExprKind::Binary(ref op, ref left, ref right) = end.node {
+                        if let BinOpKind::Add = op.node {
+                            let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left);
+                            let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right);
+
+                            if start_equal_left {
+                                take_expr = right;
+                            } else if start_equal_right {
+                                take_expr = left;
+                            }
+
+                            end_is_start_plus_val = start_equal_left | start_equal_right;
+                        }
+                    }
+
+                    if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
+                        String::new()
                     } else {
                         match limits {
                             ast::RangeLimits::Closed => {
-                                let end = sugg::Sugg::hir(cx, end, "<count>");
-                                format!(".take({})", end + sugg::ONE)
+                                let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
+                                format!(".take({})", take_expr + sugg::ONE)
                             },
-                            ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, end.span, "..")),
+                            ast::RangeLimits::HalfOpen => format!(".take({})", snippet(cx, take_expr.span, "..")),
                         }
                     }
                 } else {
-                    "".to_owned()
+                    String::new()
                 };
 
                 let (ref_mut, method) = if visitor.indexed_mut.contains(&indexed) {
@@ -1061,6 +1165,14 @@ fn check_for_loop_range<'a, 'tcx>(
                     ("", "iter")
                 };
 
+                let take_is_empty = take.is_empty();
+                let mut method_1 = take;
+                let mut method_2 = skip;
+
+                if end_is_start_plus_val {
+                    mem::swap(&mut method_1, &mut method_2);
+                }
+
                 if visitor.nonindex {
                     span_lint_and_then(
                         cx,
@@ -1073,23 +1185,29 @@ fn check_for_loop_range<'a, 'tcx>(
                                 "consider using an iterator".to_string(),
                                 vec![
                                     (pat.span, format!("({}, <item>)", ident.name)),
-                                    (arg.span, format!("{}.{}().enumerate(){}{}", indexed, method, take, skip)),
+                                    (
+                                        arg.span,
+                                        format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
+                                    ),
                                 ],
                             );
                         },
                     );
                 } else {
-                    let repl = if starts_at_zero && take.is_empty() {
+                    let repl = if starts_at_zero && take_is_empty {
                         format!("&{}{}", ref_mut, indexed)
                     } else {
-                        format!("{}.{}(){}{}", indexed, method, take, skip)
+                        format!("{}.{}(){}{}", indexed, method, method_1, method_2)
                     };
 
                     span_lint_and_then(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         expr.span,
-                        &format!("the loop variable `{}` is only used to index `{}`.", ident.name, indexed),
+                        &format!(
+                            "the loop variable `{}` is only used to index `{}`.",
+                            ident.name, indexed
+                        ),
                         |db| {
                             multispan_sugg(
                                 db,
@@ -1108,7 +1226,7 @@ fn is_len_call(expr: &Expr, var: Name) -> bool {
     if_chain! {
         if let ExprKind::MethodCall(ref method, _, ref len_args) = expr.node;
         if len_args.len() == 1;
-        if method.ident.name == "len";
+        if method.ident.name == *sym::len;
         if let ExprKind::Path(QPath::Resolved(_, ref path)) = len_args[0].node;
         if path.segments.len() == 1;
         if path.segments[0].ident.name == var;
@@ -1120,6 +1238,23 @@ fn is_len_call(expr: &Expr, var: Name) -> bool {
     false
 }
 
+fn is_end_eq_array_len(cx: &LateContext<'_, '_>, end: &Expr, limits: ast::RangeLimits, indexed_ty: Ty<'_>) -> bool {
+    if_chain! {
+        if let ExprKind::Lit(ref lit) = end.node;
+        if let ast::LitKind::Int(end_int, _) = lit.node;
+        if let ty::Array(_, arr_len_const) = indexed_ty.sty;
+        if let Some(arr_len) = arr_len_const.assert_usize(cx.tcx);
+        then {
+            return match limits {
+                ast::RangeLimits::Closed => end_int + 1 >= arr_len.into(),
+                ast::RangeLimits::HalfOpen => end_int >= arr_len.into(),
+            };
+        }
+    }
+
+    false
+}
+
 fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr, expr: &'tcx Expr) {
     // if this for loop is iterating over a two-sided range...
     if let Some(higher::Range {
@@ -1137,14 +1272,14 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
                 // smaller value.
                 let ty = cx.tables.expr_ty(start);
                 let (sup, eq) = match (start_idx, end_idx) {
-                    (
-                        Constant::Int(start_idx),
-                        Constant::Int(end_idx),
-                    ) => (match ty.sty {
-                        ty::TyInt(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
-                        ty::TyUint(_) => start_idx > end_idx,
-                        _ => false,
-                    }, start_idx == end_idx),
+                    (Constant::Int(start_idx), Constant::Int(end_idx)) => (
+                        match ty.sty {
+                            ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
+                            ty::Uint(_) => start_idx > end_idx,
+                            _ => false,
+                        },
+                        start_idx == end_idx,
+                    ),
                     _ => (false, false),
                 };
 
@@ -1173,6 +1308,7 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
                                     dots = dots,
                                     start = start_snippet
                                 ),
+                                Applicability::MaybeIncorrect,
                             );
                         },
                     );
@@ -1192,20 +1328,18 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
 }
 
 fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_name: &str) {
-    let object = snippet(cx, args[0].span, "_");
-    let muta = if method_name == "iter_mut" {
-        "mut "
-    } else {
-        ""
-    };
+    let mut applicability = Applicability::MachineApplicable;
+    let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
+    let muta = if method_name == "iter_mut" { "mut " } else { "" };
     span_lint_and_sugg(
         cx,
         EXPLICIT_ITER_LOOP,
         arg.span,
-        "it is more idiomatic to loop over references to containers instead of using explicit \
+        "it is more concise to loop over references to containers instead of using explicit \
          iteration methods",
         "to write this more concisely, try",
         format!("&{}{}", muta, object),
+        applicability,
     )
 }
 
@@ -1220,8 +1354,8 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex
                 if is_ref_iterable_type(cx, &args[0]) {
                     lint_iter_method(cx, args, arg, method_name);
                 }
-            } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
-                let def_id = cx.tables.type_dependent_defs()[arg.hir_id].def_id();
+            } else if method_name == "into_iter" && match_trait_method(cx, arg, &*paths::INTO_ITERATOR) {
+                let def_id = cx.tables.type_dependent_def_id(arg.hir_id).unwrap();
                 let substs = cx.tables.node_substs(arg.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
 
@@ -1231,22 +1365,24 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex
                     match cx.tables.expr_ty(&args[0]).sty {
                         // If the length is greater than 32 no traits are implemented for array and
                         // therefore we cannot use `&`.
-                        ty::TypeVariants::TyArray(_, size) if size.assert_usize(cx.tcx).expect("array size") > 32 => (),
+                        ty::Array(_, size) if size.assert_usize(cx.tcx).expect("array size") > 32 => (),
                         _ => lint_iter_method(cx, args, arg, method_name),
                     };
                 } else {
-                    let object = snippet(cx, args[0].span, "_");
+                    let mut applicability = Applicability::MachineApplicable;
+                    let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
                     span_lint_and_sugg(
                         cx,
                         EXPLICIT_INTO_ITER_LOOP,
                         arg.span,
-                        "it is more idiomatic to loop over containers instead of using explicit \
+                        "it is more concise to loop over containers instead of using explicit \
                          iteration methods`",
                         "to write this more concisely, try",
                         object.to_string(),
+                        applicability,
                     );
                 }
-            } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) {
+            } else if method_name == "next" && match_trait_method(cx, arg, &*paths::ITERATOR) {
                 span_lint(
                     cx,
                     ITER_NEXT_LOOP,
@@ -1263,10 +1399,10 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex
     }
 }
 
-/// Check for `for` loops over `Option`s and `Results`
+/// Checks for `for` loops over `Option`s and `Result`s.
 fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr) {
     let ty = cx.tables.expr_ty(arg);
-    if match_type(cx, ty, &paths::OPTION) {
+    if match_type(cx, ty, &*paths::OPTION) {
         span_help_and_lint(
             cx,
             FOR_LOOP_OVER_OPTION,
@@ -1282,7 +1418,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr) {
                 snippet(cx, arg.span, "_")
             ),
         );
-    } else if match_type(cx, ty, &paths::RESULT) {
+    } else if match_type(cx, ty, &*paths::RESULT) {
         span_help_and_lint(
             cx,
             FOR_LOOP_OVER_RESULT,
@@ -1303,6 +1439,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr) {
 
 fn check_for_loop_explicit_counter<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
+    pat: &'tcx Pat,
     arg: &'tcx Expr,
     body: &'tcx Expr,
     expr: &'tcx Expr,
@@ -1310,7 +1447,7 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
     // Look for variables that are incremented once per loop iteration.
     let mut visitor = IncrementVisitor {
         cx,
-        states: HashMap::new(),
+        states: FxHashMap::default(),
         depth: 0,
         done: false,
     };
@@ -1318,48 +1455,53 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
 
     // For each candidate, check the parent block to see if
     // it's initialized to zero at the start of the loop.
-    let map = &cx.tcx.hir;
-    let parent_scope = map.get_enclosing_scope(expr.id)
-        .and_then(|id| map.get_enclosing_scope(id));
-    if let Some(parent_id) = parent_scope {
-        if let NodeBlock(block) = map.get(parent_id) {
-            for (id, _) in visitor
-                .states
-                .iter()
-                .filter(|&(_, v)| *v == VarState::IncrOnce)
-            {
-                let mut visitor2 = InitializeVisitor {
-                    cx,
-                    end_expr: expr,
-                    var_id: *id,
-                    state: VarState::IncrOnce,
-                    name: None,
-                    depth: 0,
-                    past_loop: false,
-                };
-                walk_block(&mut visitor2, block);
-
-                if visitor2.state == VarState::Warn {
-                    if let Some(name) = visitor2.name {
-                        span_lint(
-                            cx,
-                            EXPLICIT_COUNTER_LOOP,
-                            expr.span,
-                            &format!(
-                                "the variable `{0}` is used as a loop counter. Consider using `for ({0}, \
-                                 item) in {1}.enumerate()` or similar iterators",
-                                name,
-                                snippet(cx, arg.span, "_")
-                            ),
-                        );
-                    }
+    if let Some(block) = get_enclosing_block(&cx, expr.hir_id) {
+        for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) {
+            let mut visitor2 = InitializeVisitor {
+                cx,
+                end_expr: expr,
+                var_id: *id,
+                state: VarState::IncrOnce,
+                name: None,
+                depth: 0,
+                past_loop: false,
+            };
+            walk_block(&mut visitor2, block);
+
+            if visitor2.state == VarState::Warn {
+                if let Some(name) = visitor2.name {
+                    let mut applicability = Applicability::MachineApplicable;
+                    span_lint_and_sugg(
+                        cx,
+                        EXPLICIT_COUNTER_LOOP,
+                        expr.span,
+                        &format!("the variable `{}` is used as a loop counter.", name),
+                        "consider using",
+                        format!(
+                            "for ({}, {}) in {}.enumerate()",
+                            name,
+                            snippet_with_applicability(cx, pat.span, "item", &mut applicability),
+                            if higher::range(cx, arg).is_some() {
+                                format!(
+                                    "({})",
+                                    snippet_with_applicability(cx, arg.span, "_", &mut applicability)
+                                )
+                            } else {
+                                format!(
+                                    "{}",
+                                    sugg::Sugg::hir_with_applicability(cx, arg, "_", &mut applicability).maybe_par()
+                                )
+                            }
+                        ),
+                        applicability,
+                    );
                 }
             }
         }
     }
 }
 
-/// Check for the `FOR_KV_MAP` lint.
+/// Checks for the `FOR_KV_MAP` lint.
 fn check_for_loop_over_map_kv<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     pat: &'tcx Pat,
@@ -1373,7 +1515,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
         if pat.len() == 2 {
             let arg_span = arg.span;
             let (new_pat_span, kind, ty, mutbl) = match cx.tables.expr_ty(arg).sty {
-                ty::TyRef(_, ty, mutbl) => match (&pat[0].node, &pat[1].node) {
+                ty::Ref(_, ty, mutbl) => match (&pat[0].node, &pat[1].node) {
                     (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl),
                     (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, MutImmutable),
                     _ => return,
@@ -1389,7 +1531,7 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
                 _ => arg,
             };
 
-            if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP) {
+            if match_type(cx, ty, &*paths::HASHMAP) || match_type(cx, ty, &*paths::BTREEMAP) {
                 span_lint_and_then(
                     cx,
                     FOR_KV_MAP,
@@ -1413,44 +1555,44 @@ fn check_for_loop_over_map_kv<'a, 'tcx>(
 }
 
 struct MutatePairDelegate {
-    node_id_low: Option<NodeId>,
-    node_id_high: Option<NodeId>,
+    hir_id_low: Option<HirId>,
+    hir_id_high: Option<HirId>,
     span_low: Option<Span>,
     span_high: Option<Span>,
 }
 
 impl<'tcx> Delegate<'tcx> for MutatePairDelegate {
-    fn consume(&mut self, _: NodeId, _: Span, _: &cmt_<'tcx>, _: ConsumeMode) {}
+    fn consume(&mut self, _: HirId, _: Span, _: &cmt_<'tcx>, _: ConsumeMode) {}
 
     fn matched_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: MatchMode) {}
 
     fn consume_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: ConsumeMode) {}
 
-    fn borrow(&mut self, _: NodeId, sp: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, bk: ty::BorrowKind, _: LoanCause) {
+    fn borrow(&mut self, _: HirId, sp: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, bk: ty::BorrowKind, _: LoanCause) {
         if let ty::BorrowKind::MutBorrow = bk {
             if let Categorization::Local(id) = cmt.cat {
-                if Some(id) == self.node_id_low {
+                if Some(id) == self.hir_id_low {
                     self.span_low = Some(sp)
                 }
-                if Some(id) == self.node_id_high {
+                if Some(id) == self.hir_id_high {
                     self.span_high = Some(sp)
                 }
             }
         }
     }
 
-    fn mutate(&mut self, _: NodeId, sp: Span, cmt: &cmt_<'tcx>, _: MutateMode) {
+    fn mutate(&mut self, _: HirId, sp: Span, cmt: &cmt_<'tcx>, _: MutateMode) {
         if let Categorization::Local(id) = cmt.cat {
-            if Some(id) == self.node_id_low {
+            if Some(id) == self.hir_id_low {
                 self.span_low = Some(sp)
             }
-            if Some(id) == self.node_id_high {
+            if Some(id) == self.hir_id_high {
                 self.span_high = Some(sp)
             }
         }
     }
 
-    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
+    fn decl_without_init(&mut self, _: HirId, _: Span) {}
 }
 
 impl<'tcx> MutatePairDelegate {
@@ -1466,10 +1608,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_, '_>, arg: &Expr, body: &Expr)
         ..
     }) = higher::range(cx, arg)
     {
-        let mut_ids = vec![
-            check_for_mutability(cx, start),
-            check_for_mutability(cx, end),
-        ];
+        let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
         if mut_ids[0].is_some() || mut_ids[1].is_some() {
             let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
             mut_warn_with_span(cx, span_low);
@@ -1489,17 +1628,17 @@ fn mut_warn_with_span(cx: &LateContext<'_, '_>, span: Option<Span>) {
     }
 }
 
-fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<NodeId> {
+fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<HirId> {
     if_chain! {
         if let ExprKind::Path(ref qpath) = bound.node;
         if let QPath::Resolved(None, _) = *qpath;
         then {
-            let def = cx.tables.qpath_def(qpath, bound.hir_id);
-            if let Def::Local(node_id) = def {
-                let node_str = cx.tcx.hir.get(node_id);
+            let res = cx.tables.qpath_res(qpath, bound.hir_id);
+            if let Res::Local(node_id) = res {
+                let node_str = cx.tcx.hir().get_by_hir_id(node_id);
                 if_chain! {
-                    if let map::Node::NodeBinding(pat) = node_str;
-                    if let PatKind::Binding(bind_ann, _, _, _) = pat.node;
+                    if let Node::Binding(pat) = node_str;
+                    if let PatKind::Binding(bind_ann, ..) = pat.node;
                     if let BindingAnnotation::Mutable = bind_ann;
                     then {
                         return Some(node_id);
@@ -1511,10 +1650,14 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<NodeId
     None
 }
 
-fn check_for_mutation(cx: &LateContext<'_, '_>, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) {
+fn check_for_mutation(
+    cx: &LateContext<'_, '_>,
+    body: &Expr,
+    bound_ids: &[Option<HirId>],
+) -> (Option<Span>, Option<Span>) {
     let mut delegate = MutatePairDelegate {
-        node_id_low: bound_ids[0],
-        node_id_high: bound_ids[1],
+        hir_id_low: bound_ids[0],
+        hir_id_high: bound_ids[1],
         span_low: None,
         span_high: None,
     };
@@ -1524,11 +1667,11 @@ fn check_for_mutation(cx: &LateContext<'_, '_>, body: &Expr, bound_ids: &[Option
     delegate.mutation_span()
 }
 
-/// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`.
+/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`.
 fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool {
     match *pat {
         PatKind::Wild => true,
-        PatKind::Binding(_, _, ident, None) if ident.as_str().starts_with('_') => {
+        PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => {
             let mut visitor = UsedVisitor {
                 var: ident.name,
                 used: false,
@@ -1561,7 +1704,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
 struct LocalUsedVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    local: ast::NodeId,
+    local: HirId,
     used: bool,
 }
 
@@ -1583,17 +1726,17 @@ struct VarVisitor<'a, 'tcx: 'a> {
     /// context reference
     cx: &'a LateContext<'a, 'tcx>,
     /// var name to look for as index
-    var: ast::NodeId,
+    var: HirId,
     /// indexed variables that are used mutably
-    indexed_mut: HashSet<Name>,
+    indexed_mut: FxHashSet<Name>,
     /// indirectly indexed variables (`v[(i + 4) % N]`), the extend is `None` for global
-    indexed_indirectly: HashMap<Name, Option<region::Scope>>,
+    indexed_indirectly: FxHashMap<Name, Option<region::Scope>>,
     /// subset of `indexed` of vars that are indexed directly: `v[i]`
     /// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]`
-    indexed_directly: HashMap<Name, Option<region::Scope>>,
+    indexed_directly: FxHashMap<Name, (Option<region::Scope>, Ty<'tcx>)>,
     /// Any names that are used outside an index operation.
     /// Used to detect things like `&mut vec` used together with `vec[i]`
-    referenced: HashSet<Name>,
+    referenced: FxHashSet<Name>,
     /// has the loop variable been used in expressions other than the index of
     /// an index op?
     nonindex: bool,
@@ -1625,28 +1768,32 @@ fn check(&mut self, idx: &'tcx Expr, seqexpr: &'tcx Expr, expr: &'tcx Expr) -> b
                     if self.prefer_mutable {
                         self.indexed_mut.insert(seqvar.segments[0].ident.name);
                     }
-                    let def = self.cx.tables.qpath_def(seqpath, seqexpr.hir_id);
-                    match def {
-                        Def::Local(node_id) | Def::Upvar(node_id, ..) => {
-                            let hir_id = self.cx.tcx.hir.node_to_hir_id(node_id);
-
-                            let parent_id = self.cx.tcx.hir.get_parent(expr.id);
-                            let parent_def_id = self.cx.tcx.hir.local_def_id(parent_id);
+                    let res = self.cx.tables.qpath_res(seqpath, seqexpr.hir_id);
+                    match res {
+                        Res::Local(hir_id) | Res::Upvar(hir_id, ..) => {
+                            let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
+                            let parent_def_id = self.cx.tcx.hir().local_def_id_from_hir_id(parent_id);
                             let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id);
                             if indexed_indirectly {
                                 self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
                             }
                             if index_used_directly {
-                                self.indexed_directly.insert(seqvar.segments[0].ident.name, Some(extent));
+                                self.indexed_directly.insert(
+                                    seqvar.segments[0].ident.name,
+                                    (Some(extent), self.cx.tables.node_type(seqexpr.hir_id)),
+                                );
                             }
                             return false;  // no need to walk further *on the variable*
                         }
-                        Def::Static(..) | Def::Const(..) => {
+                        Res::Def(DefKind::Static, ..) | Res::Def(DefKind::Const, ..) => {
                             if indexed_indirectly {
                                 self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
                             }
                             if index_used_directly {
-                                self.indexed_directly.insert(seqvar.segments[0].ident.name, None);
+                                self.indexed_directly.insert(
+                                    seqvar.segments[0].ident.name,
+                                    (None, self.cx.tables.node_type(seqexpr.hir_id)),
+                                );
                             }
                             return false;  // no need to walk further *on the variable*
                         }
@@ -1664,8 +1811,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         if_chain! {
             // a range index op
             if let ExprKind::MethodCall(ref meth, _, ref args) = expr.node;
-            if (meth.ident.name == "index" && match_trait_method(self.cx, expr, &paths::INDEX))
-                || (meth.ident.name == "index_mut" && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
+            if (meth.ident.name == *sym::index && match_trait_method(self.cx, expr, &*paths::INDEX))
+                || (meth.ident.name == *sym::index_mut && match_trait_method(self.cx, expr, &*paths::INDEX_MUT));
             if !self.check(&args[1], &args[0], expr);
             then { return }
         }
@@ -1682,21 +1829,32 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
             if let ExprKind::Path(ref qpath) = expr.node;
             if let QPath::Resolved(None, ref path) = *qpath;
             if path.segments.len() == 1;
-            if let Def::Local(local_id) = self.cx.tables.qpath_def(qpath, expr.hir_id);
             then {
-                if local_id == self.var {
-                    // we are not indexing anything, record that
-                    self.nonindex = true;
-                } else {
-                    // not the correct variable, but still a variable
-                    self.referenced.insert(path.segments[0].ident.name);
+                match self.cx.tables.qpath_res(qpath, expr.hir_id) {
+                    Res::Upvar(local_id, ..) => {
+                        if local_id == self.var {
+                            // we are not indexing anything, record that
+                            self.nonindex = true;
+                        }
+                    }
+                    Res::Local(local_id) =>
+                    {
+
+                        if local_id == self.var {
+                            self.nonindex = true;
+                        } else {
+                            // not the correct variable, but still a variable
+                            self.referenced.insert(path.segments[0].ident.name);
+                        }
+                    }
+                    _ => {}
                 }
             }
         }
+
         let old = self.prefer_mutable;
         match expr.node {
-            ExprKind::AssignOp(_, ref lhs, ref rhs) |
-            ExprKind::Assign(ref lhs, ref rhs) => {
+            ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs) => {
                 self.prefer_mutable = true;
                 self.visit_expr(lhs);
                 self.prefer_mutable = false;
@@ -1713,7 +1871,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                 for expr in args {
                     let ty = self.cx.tables.expr_ty_adjusted(expr);
                     self.prefer_mutable = false;
-                    if let ty::TyRef(_, _, mutbl) = ty.sty {
+                    if let ty::Ref(_, _, mutbl) = ty.sty {
                         if mutbl == MutMutable {
                             self.prefer_mutable = true;
                         }
@@ -1722,10 +1880,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                 }
             },
             ExprKind::MethodCall(_, _, ref args) => {
-                let def_id = self.cx.tables.type_dependent_defs()[expr.hir_id].def_id();
+                let def_id = self.cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
                 for (ty, expr) in self.cx.tcx.fn_sig(def_id).inputs().skip_binder().iter().zip(args) {
                     self.prefer_mutable = false;
-                    if let ty::TyRef(_, _, mutbl) = ty.sty {
+                    if let ty::Ref(_, _, mutbl) = ty.sty {
                         if mutbl == MutMutable {
                             self.prefer_mutable = true;
                         }
@@ -1733,6 +1891,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                     self.visit_expr(expr);
                 }
             },
+            ExprKind::Closure(_, _, body_id, ..) => {
+                let body = self.cx.tcx.hir().body(body_id);
+                self.visit_expr(&body.value);
+            },
             _ => walk_expr(self, expr),
         }
         self.prefer_mutable = old;
@@ -1742,6 +1904,19 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
+fn is_used_inside<'a, 'tcx: 'a>(cx: &'a LateContext<'a, 'tcx>, expr: &'tcx Expr, container: &'tcx Expr) -> bool {
+    let def_id = match var_def_id(cx, expr) {
+        Some(id) => id,
+        None => return false,
+    };
+    if let Some(used_mutably) = mutated_variables(container, cx) {
+        if used_mutably.contains(&def_id) {
+            return true;
+        }
+    }
+    false
+}
+
 fn is_iterator_used_after_while_let<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, iter_expr: &'tcx Expr) -> bool {
     let def_id = match var_def_id(cx, iter_expr) {
         Some(id) => id,
@@ -1750,7 +1925,7 @@ fn is_iterator_used_after_while_let<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, it
     let mut visitor = VarUsedAfterLoopVisitor {
         cx,
         def_id,
-        iter_expr_id: iter_expr.id,
+        iter_expr_id: iter_expr.hir_id,
         past_while_let: false,
         var_used_after_while_let: false,
     };
@@ -1762,8 +1937,8 @@ fn is_iterator_used_after_while_let<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, it
 
 struct VarUsedAfterLoopVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    def_id: NodeId,
-    iter_expr_id: NodeId,
+    def_id: HirId,
+    iter_expr_id: HirId,
     past_while_let: bool,
     var_used_after_while_let: bool,
 }
@@ -1774,7 +1949,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
             if Some(self.def_id) == var_def_id(self.cx, expr) {
                 self.var_used_after_while_let = true;
             }
-        } else if self.iter_expr_id == expr.id {
+        } else if self.iter_expr_id == expr.hir_id {
             self.past_while_let = true;
         }
         walk_expr(self, expr);
@@ -1784,29 +1959,28 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-
-/// Return true if the type of expr is one that provides `IntoIterator` impls
+/// Returns `true` if the type of expr is one that provides `IntoIterator` impls
 /// for `&T` and `&mut T`, such as `Vec`.
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
     // no walk_ptrs_ty: calling iter() on a reference can make sense because it
     // will allow further borrows afterwards
     let ty = cx.tables.expr_ty(e);
     is_iterable_array(ty, cx) ||
-    match_type(cx, ty, &paths::VEC) ||
-    match_type(cx, ty, &paths::LINKED_LIST) ||
-    match_type(cx, ty, &paths::HASHMAP) ||
-    match_type(cx, ty, &paths::HASHSET) ||
-    match_type(cx, ty, &paths::VEC_DEQUE) ||
-    match_type(cx, ty, &paths::BINARY_HEAP) ||
-    match_type(cx, ty, &paths::BTREEMAP) ||
-    match_type(cx, ty, &paths::BTREESET)
+    match_type(cx, ty, &*paths::VEC) ||
+    match_type(cx, ty, &*paths::LINKED_LIST) ||
+    match_type(cx, ty, &*paths::HASHMAP) ||
+    match_type(cx, ty, &*paths::HASHSET) ||
+    match_type(cx, ty, &*paths::VEC_DEQUE) ||
+    match_type(cx, ty, &*paths::BINARY_HEAP) ||
+    match_type(cx, ty, &*paths::BTREEMAP) ||
+    match_type(cx, ty, &*paths::BTREESET)
 }
 
 fn is_iterable_array(ty: Ty<'_>, cx: &LateContext<'_, '_>) -> bool {
     // IntoIterator is currently only implemented for array sizes <= 32 in rustc
     match ty.sty {
-        ty::TyArray(_, n) => (0..=32).contains(&n.assert_usize(cx.tcx).expect("array length")),
+        ty::Array(_, n) => (0..=32).contains(&n.assert_usize(cx.tcx).expect("array length")),
         _ => false,
     }
 }
@@ -1817,13 +1991,9 @@ fn extract_expr_from_first_stmt(block: &Block) -> Option<&Expr> {
     if block.stmts.is_empty() {
         return None;
     }
-    if let StmtKind::Decl(ref decl, _) = block.stmts[0].node {
-        if let DeclKind::Local(ref local) = decl.node {
-            if let Some(ref expr) = local.init {
-                Some(expr)
-            } else {
-                None
-            }
+    if let StmtKind::Local(ref local) = block.stmts[0].node {
+        if let Some(ref expr) = local.init {
+            Some(expr)
         } else {
             None
         }
@@ -1837,14 +2007,14 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
     match block.expr {
         Some(ref expr) if block.stmts.is_empty() => Some(expr),
         None if !block.stmts.is_empty() => match block.stmts[0].node {
-            StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => Some(expr),
-            StmtKind::Decl(..) => None,
+            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => Some(expr),
+            StmtKind::Local(..) | StmtKind::Item(..) => None,
         },
         _ => None,
     }
 }
 
-/// Return true if expr contains a single break expr without destination label
+/// Returns `true` if expr contains a single break expr without destination label
 /// and
 /// passed expression. The expression may be within a block.
 fn is_simple_break_expr(expr: &Expr) -> bool {
@@ -1861,7 +2031,7 @@ fn is_simple_break_expr(expr: &Expr) -> bool {
 // To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
 // incremented exactly once in the loop body, and initialized to zero
 // at the start of the loop.
-#[derive(PartialEq)]
+#[derive(Debug, PartialEq)]
 enum VarState {
     Initial,  // Not examined yet
     IncrOnce, // Incremented exactly once, may be a loop counter
@@ -1872,9 +2042,9 @@ enum VarState {
 
 /// Scan a for loop for variables that are incremented exactly once.
 struct IncrementVisitor<'a, 'tcx: 'a> {
-    cx: &'a LateContext<'a, 'tcx>,     // context reference
-    states: HashMap<NodeId, VarState>, // incremented variables
-    depth: u32,                        // depth of conditional expressions
+    cx: &'a LateContext<'a, 'tcx>,      // context reference
+    states: FxHashMap<HirId, VarState>, // incremented variables
+    depth: u32,                         // depth of conditional expressions
     done: bool,
 }
 
@@ -1891,7 +2061,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
 
                 match parent.node {
                     ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                        if lhs.id == expr.id {
+                        if lhs.hir_id == expr.hir_id {
                             if op.node == BinOpKind::Add && is_integer_literal(rhs, 1) {
                                 *state = match *state {
                                     VarState::Initial if self.depth == 0 => VarState::IncrOnce,
@@ -1903,20 +2073,19 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                             }
                         }
                     },
-                    ExprKind::Assign(ref lhs, _) if lhs.id == expr.id => *state = VarState::DontWarn,
+                    ExprKind::Assign(ref lhs, _) if lhs.hir_id == expr.hir_id => *state = VarState::DontWarn,
                     ExprKind::AddrOf(mutability, _) if mutability == MutMutable => *state = VarState::DontWarn,
                     _ => (),
                 }
             }
-        } else if is_loop(expr) {
-            self.states.clear();
-            self.done = true;
-            return;
-        } else if is_conditional(expr) {
+        } else if is_loop(expr) || is_conditional(expr) {
             self.depth += 1;
             walk_expr(self, expr);
             self.depth -= 1;
             return;
+        } else if let ExprKind::Continue(_) = expr.node {
+            self.done = true;
+            return;
         }
         walk_expr(self, expr);
     }
@@ -1925,11 +2094,11 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-/// Check whether a variable is initialized to zero at the start of a loop.
+/// Checks whether a variable is initialized to zero at the start of a loop.
 struct InitializeVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>, // context reference
     end_expr: &'tcx Expr,          // the for loop. Stop scanning here.
-    var_id: NodeId,
+    var_id: HirId,
     state: VarState,
     name: Option<Name>,
     depth: u32, // depth of conditional expressions
@@ -1937,11 +2106,11 @@ struct InitializeVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
-    fn visit_decl(&mut self, decl: &'tcx Decl) {
+    fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
         // Look for declarations of the variable
-        if let DeclKind::Local(ref local) = decl.node {
-            if local.pat.id == self.var_id {
-                if let PatKind::Binding(_, _, ident, _) = local.pat.node {
+        if let StmtKind::Local(ref local) = stmt.node {
+            if local.pat.hir_id == self.var_id {
+                if let PatKind::Binding(.., ident, _) = local.pat.node {
                     self.name = Some(ident.name);
 
                     self.state = if let Some(ref init) = local.init {
@@ -1956,7 +2125,7 @@ fn visit_decl(&mut self, decl: &'tcx Decl) {
                 }
             }
         }
-        walk_decl(self, decl);
+        walk_stmt(self, stmt);
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
@@ -1977,10 +2146,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         if var_def_id(self.cx, expr) == Some(self.var_id) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
                 match parent.node {
-                    ExprKind::AssignOp(_, ref lhs, _) if lhs.id == expr.id => {
+                    ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => {
                         self.state = VarState::DontWarn;
                     },
-                    ExprKind::Assign(ref lhs, ref rhs) if lhs.id == expr.id => {
+                    ExprKind::Assign(ref lhs, ref rhs) if lhs.hir_id == expr.hir_id => {
                         self.state = if is_integer_literal(rhs, 0) && self.depth == 0 {
                             VarState::Warn
                         } else {
@@ -2012,10 +2181,10 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-fn var_def_id(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<NodeId> {
+fn var_def_id(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<HirId> {
     if let ExprKind::Path(ref qpath) = expr.node {
-        let path_res = cx.tables.qpath_def(qpath, expr.hir_id);
-        if let Def::Local(node_id) = path_res {
+        let path_res = cx.tables.qpath_res(qpath, expr.hir_id);
+        if let Res::Local(node_id) = path_res {
             return Some(node_id);
         }
     }
@@ -2031,15 +2200,16 @@ fn is_loop(expr: &Expr) -> bool {
 
 fn is_conditional(expr: &Expr) -> bool {
     match expr.node {
-        ExprKind::If(..) | ExprKind::Match(..) => true,
+        ExprKind::Match(..) => true,
         _ => false,
     }
 }
 
 fn is_nested(cx: &LateContext<'_, '_>, match_expr: &Expr, iter_expr: &Expr) -> bool {
     if_chain! {
-        if let Some(loop_block) = get_enclosing_block(cx, match_expr.id);
-        if let Some(map::Node::NodeExpr(loop_expr)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(loop_block.id));
+        if let Some(loop_block) = get_enclosing_block(cx, match_expr.hir_id);
+        let parent_node = cx.tcx.hir().get_parent_node_by_hir_id(loop_block.hir_id);
+        if let Some(Node::Expr(loop_expr)) = cx.tcx.hir().find_by_hir_id(parent_node);
         then {
             return is_loop_nested(cx, loop_expr, iter_expr)
         }
@@ -2048,27 +2218,27 @@ fn is_nested(cx: &LateContext<'_, '_>, match_expr: &Expr, iter_expr: &Expr) -> b
 }
 
 fn is_loop_nested(cx: &LateContext<'_, '_>, loop_expr: &Expr, iter_expr: &Expr) -> bool {
-    let mut id = loop_expr.id;
+    let mut id = loop_expr.hir_id;
     let iter_name = if let Some(name) = path_name(iter_expr) {
         name
     } else {
         return true;
     };
     loop {
-        let parent = cx.tcx.hir.get_parent_node(id);
+        let parent = cx.tcx.hir().get_parent_node_by_hir_id(id);
         if parent == id {
             return false;
         }
-        match cx.tcx.hir.find(parent) {
-            Some(NodeExpr(expr)) => match expr.node {
+        match cx.tcx.hir().find_by_hir_id(parent) {
+            Some(Node::Expr(expr)) => match expr.node {
                 ExprKind::Loop(..) | ExprKind::While(..) => {
                     return true;
                 },
                 _ => (),
             },
-            Some(NodeBlock(block)) => {
+            Some(Node::Block(block)) => {
                 let mut block_visitor = LoopNestVisitor {
-                    id,
+                    hir_id: id,
                     iterator: iter_name,
                     nesting: Unknown,
                 };
@@ -2077,7 +2247,7 @@ fn is_loop_nested(cx: &LateContext<'_, '_>, loop_expr: &Expr, iter_expr: &Expr)
                     return false;
                 }
             },
-            Some(NodeStmt(_)) => (),
+            Some(Node::Stmt(_)) => (),
             _ => {
                 return false;
             },
@@ -2096,14 +2266,14 @@ enum Nesting {
 use self::Nesting::{LookFurther, RuledOut, Unknown};
 
 struct LoopNestVisitor {
-    id: NodeId,
+    hir_id: HirId,
     iterator: Name,
     nesting: Nesting,
 }
 
 impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
     fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
-        if stmt.node.id() == self.id {
+        if stmt.hir_id == self.hir_id {
             self.nesting = LookFurther;
         } else if self.nesting == Unknown {
             walk_stmt(self, stmt);
@@ -2114,13 +2284,15 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         if self.nesting != Unknown {
             return;
         }
-        if expr.id == self.id {
+        if expr.hir_id == self.hir_id {
             self.nesting = LookFurther;
             return;
         }
         match expr.node {
-            ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => if match_var(path, self.iterator) {
-                self.nesting = RuledOut;
+            ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => {
+                if match_var(path, self.iterator) {
+                    self.nesting = RuledOut;
+                }
             },
             _ => walk_expr(self, expr),
         }
@@ -2130,7 +2302,7 @@ fn visit_pat(&mut self, pat: &'tcx Pat) {
         if self.nesting != Unknown {
             return;
         }
-        if let PatKind::Binding(_, _, span_name, _) = pat.node {
+        if let PatKind::Binding(.., span_name, _) = pat.node {
             if self.iterator == span_name.name {
                 self.nesting = RuledOut;
                 return;
@@ -2156,14 +2328,14 @@ fn path_name(e: &Expr) -> Option<Name> {
 
 fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, expr: &'tcx Expr) {
     if constant(cx, cx.tables, cond).is_some() {
-        // A pure constant condition (e.g. while false) is not linted.
+        // A pure constant condition (e.g., `while false`) is not linted.
         return;
     }
 
     let mut var_visitor = VarCollectorVisitor {
         cx,
-        ids: HashSet::new(),
-        def_ids: HashMap::new(),
+        ids: FxHashSet::default(),
+        def_ids: FxHashMap::default(),
         skip: false,
     };
     var_visitor.visit_expr(cond);
@@ -2174,7 +2346,7 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
     let no_cond_variable_mutated = if let Some(used_mutably) = mutated_variables(expr, cx) {
         used_in_condition.is_disjoint(&used_mutably)
     } else {
-        return
+        return;
     };
     let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
     if no_cond_variable_mutated && !mutable_static_in_cond {
@@ -2182,7 +2354,8 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
             cx,
             WHILE_IMMUTABLE_CONDITION,
             cond.span,
-            "Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.",
+            "Variable in the condition are not mutated in the loop body. \
+             This either leads to an infinite or to a never running loop.",
         );
     }
 }
@@ -2193,8 +2366,8 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
 /// All variables definition IDs are collected
 struct VarCollectorVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    ids: HashSet<NodeId>,
-    def_ids: HashMap<def_id::DefId, bool>,
+    ids: FxHashSet<HirId>,
+    def_ids: FxHashMap<def_id::DefId, bool>,
     skip: bool,
 }
 
@@ -2203,13 +2376,14 @@ fn insert_def_id(&mut self, ex: &'tcx Expr) {
         if_chain! {
             if let ExprKind::Path(ref qpath) = ex.node;
             if let QPath::Resolved(None, _) = *qpath;
-            let def = self.cx.tables.qpath_def(qpath, ex.hir_id);
+            let res = self.cx.tables.qpath_res(qpath, ex.hir_id);
             then {
-                match def {
-                    Def::Local(node_id) | Def::Upvar(node_id, ..) => {
+                match res {
+                    Res::Local(node_id) | Res::Upvar(node_id, ..) => {
                         self.ids.insert(node_id);
                     },
-                    Def::Static(def_id, mutable) => {
+                    Res::Def(DefKind::Static, def_id) => {
+                        let mutable = self.cx.tcx.is_mutable_static(def_id);
                         self.def_ids.insert(def_id, mutable);
                     },
                     _ => {},
@@ -2234,3 +2408,71 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
 }
+
+const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
+
+fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr, cx: &LateContext<'a, 'tcx>) {
+    if_chain! {
+        if let ExprKind::MethodCall(ref method, _, ref args) = expr.node;
+        if let ExprKind::MethodCall(ref chain_method, _, _) = args[0].node;
+        if chain_method.ident.name == *sym::collect && match_trait_method(cx, &args[0], &*paths::ITERATOR);
+        if let Some(ref generic_args) = chain_method.args;
+        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
+        then {
+            let ty = cx.tables.node_type(ty.hir_id);
+            if match_type(cx, ty, &*paths::VEC) ||
+                match_type(cx, ty, &*paths::VEC_DEQUE) ||
+                match_type(cx, ty, &*paths::BTREEMAP) ||
+                match_type(cx, ty, &*paths::HASHMAP) {
+                if method.ident.name == *sym::len {
+                    let span = shorten_needless_collect_span(expr);
+                    span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |db| {
+                        db.span_suggestion(
+                            span,
+                            "replace with",
+                            ".count()".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    });
+                }
+                if method.ident.name == *sym::is_empty {
+                    let span = shorten_needless_collect_span(expr);
+                    span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |db| {
+                        db.span_suggestion(
+                            span,
+                            "replace with",
+                            ".next().is_none()".to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    });
+                }
+                if method.ident.name == *sym::contains {
+                    let contains_arg = snippet(cx, args[1].span, "??");
+                    let span = shorten_needless_collect_span(expr);
+                    span_lint_and_then(cx, NEEDLESS_COLLECT, span, NEEDLESS_COLLECT_MSG, |db| {
+                        db.span_suggestion(
+                            span,
+                            "replace with",
+                            format!(
+                                ".any(|&x| x == {})",
+                                if contains_arg.starts_with('&') { &contains_arg[1..] } else { &contains_arg }
+                            ),
+                            Applicability::MachineApplicable,
+                        );
+                    });
+                }
+            }
+        }
+    }
+}
+
+fn shorten_needless_collect_span(expr: &Expr) -> Span {
+    if_chain! {
+        if let ExprKind::MethodCall(_, _, ref args) = expr.node;
+        if let ExprKind::MethodCall(_, ref span, _) = args[0].node;
+        then {
+            return expr.span.with_lo(span.lo() - BytePos(1));
+        }
+    }
+    unreachable!()
+}
index d8b14db605f291c240626e8b10dd6537ddc7ca49..80cfde7cac561e006948768be622270f13924820 100644 (file)
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+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,
+};
 use if_chain::if_chain;
-use rustc::hir::*;
+use rustc::hir;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use syntax::ast;
-use crate::utils::{get_arg_ident, is_adjusted, iter_input_pats, match_qpath, match_trait_method, match_type,
-            paths, remove_blocks, snippet, span_help_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::Ident;
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for mapping `clone()` over an iterator.
-///
-/// **Why is this bad?** It makes the code less readable than using the
-/// `.cloned()` adapter.
-///
-/// **Known problems:** Sometimes `.cloned()` requires stricter trait
-/// bound than `.map(|e| e.clone())` (which works because of the coercion).
-/// See [#498](https://github.com/rust-lang-nursery/rust-clippy/issues/498).
-///
-/// **Example:**
-/// ```rust
-/// x.map(|e| e.clone());
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
+    /// `iterator.cloned()` instead
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x = vec![42, 43];
+    /// let y = x.iter();
+    /// let z = y.map(|i| *i);
+    /// ```
+    ///
+    /// The correct use would be:
+    ///
+    /// ```rust
+    /// let x = vec![42, 43];
+    /// let y = x.iter();
+    /// let z = y.cloned();
+    /// ```
     pub MAP_CLONE,
     style,
-    "using `.map(|x| x.clone())` to clone an iterator or option's contents"
+    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
+declare_lint_pass!(MapClone => [MAP_CLONE]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        // call to .map()
-        if let ExprKind::MethodCall(ref method, _, ref args) = expr.node {
-            if method.ident.name == "map" && args.len() == 2 {
-                match args[1].node {
-                    ExprKind::Closure(_, ref decl, closure_eid, _, _) => {
-                        let body = cx.tcx.hir.body(closure_eid);
-                        let closure_expr = remove_blocks(&body.value);
-                        if_chain! {
-                            // nothing special in the argument, besides reference bindings
-                            // (e.g. .map(|&x| x) )
-                            if let Some(first_arg) = iter_input_pats(decl, body).next();
-                            if let Some(arg_ident) = get_arg_ident(&first_arg.pat);
-                            // the method is being called on a known type (option or iterator)
-                            if let Some(type_name) = get_type_name(cx, expr, &args[0]);
-                            then {
-                                // We know that body.arguments is not empty at this point
-                                let ty = cx.tables.pat_ty(&body.arguments[0].pat);
-                                // look for derefs, for .map(|x| *x)
-                                if only_derefs(cx, &*closure_expr, arg_ident) &&
-                                    // .cloned() only removes one level of indirection, don't lint on more
-                                    walk_ptrs_ty_depth(cx.tables.pat_ty(&first_arg.pat)).1 == 1
-                                {
-                                    // the argument is not an &mut T
-                                    if let ty::TyRef(_, _, mutbl) = ty.sty {
-                                        if mutbl == MutImmutable {
-                                            span_help_and_lint(cx, MAP_CLONE, expr.span, &format!(
-                                                "you seem to be using .map() to clone the contents of an {}, consider \
-                                                using `.cloned()`", type_name),
-                                                &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")));
-                                        }
-                                    }
+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) {
+            return;
+        }
+
+        if_chain! {
+            if let hir::ExprKind::MethodCall(ref method, _, ref args) = e.node;
+            if args.len() == 2;
+            if method.ident.as_str() == "map";
+            let ty = cx.tables.expr_ty(&args[0]);
+            if match_type(cx, ty, &*paths::OPTION) || match_trait_method(cx, e, &*paths::ITERATOR);
+            if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].node;
+            let closure_body = cx.tcx.hir().body(body_id);
+            let closure_expr = remove_blocks(&closure_body.value);
+            then {
+                match closure_body.arguments[0].pat.node {
+                    hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(
+                        hir::BindingAnnotation::Unannotated, .., name, None
+                    ) = inner.node {
+                        if ident_eq(name, closure_expr) {
+                            lint(cx, e.span, args[0].span, true);
+                        }
+                    },
+                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
+                        match closure_expr.node {
+                            hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
+                                if ident_eq(name, inner) && !cx.tables.expr_ty(inner).is_box() {
+                                    lint(cx, e.span, args[0].span, true);
                                 }
-                                // explicit clone() calls ( .map(|x| x.clone()) )
-                                else if let ExprKind::MethodCall(ref clone_call, _, ref clone_args) = closure_expr.node {
-                                    if clone_call.ident.name == "clone" &&
-                                        clone_args.len() == 1 &&
-                                        match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) &&
-                                        expr_eq_name(cx, &clone_args[0], arg_ident)
-                                    {
-                                        span_help_and_lint(cx, MAP_CLONE, expr.span, &format!(
-                                            "you seem to be using .map() to clone the contents of an {}, consider \
-                                            using `.cloned()`", type_name),
-                                            &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")));
+                            },
+                            hir::ExprKind::MethodCall(ref method, _, ref obj) => {
+                                if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone"
+                                    && match_trait_method(cx, closure_expr, &*paths::CLONE_TRAIT) {
+
+                                    let obj_ty = cx.tables.expr_ty(&obj[0]);
+                                    if let ty::Ref(_, ty, _) = obj_ty.sty {
+                                        let copy = is_copy(cx, ty);
+                                        lint(cx, e.span, args[0].span, copy);
+                                    } else {
+                                        lint_needless_cloning(cx, e.span, args[0].span);
                                     }
                                 }
-                            }
+                            },
+                            _ => {},
                         }
                     },
-                    ExprKind::Path(ref path) => if match_qpath(path, &paths::CLONE) {
-                        let type_name = get_type_name(cx, expr, &args[0]).unwrap_or("_");
-                        span_help_and_lint(
-                            cx,
-                            MAP_CLONE,
-                            expr.span,
-                            &format!(
-                                "you seem to be using .map() to clone the contents of an \
-                                 {}, consider using `.cloned()`",
-                                type_name
-                            ),
-                            &format!("try\n{}.cloned()", snippet(cx, args[0].span, "..")),
-                        );
-                    },
-                    _ => (),
+                    _ => {},
                 }
             }
         }
     }
 }
 
-fn expr_eq_name(cx: &LateContext<'_, '_>, expr: &Expr, id: ast::Ident) -> bool {
-    match expr.node {
-        ExprKind::Path(QPath::Resolved(None, ref path)) => {
-            let arg_segment = [
-                PathSegment {
-                    ident: id,
-                    args: None,
-                    infer_types: true,
-                },
-            ];
-            !path.is_global() && SpanlessEq::new(cx).eq_path_segments(&path.segments[..], &arg_segment)
-        },
-        _ => false,
-    }
-}
-
-fn get_type_name(cx: &LateContext<'_, '_>, expr: &Expr, arg: &Expr) -> Option<&'static str> {
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        Some("iterator")
-    } else if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(arg)), &paths::OPTION) {
-        Some("Option")
+fn ident_eq(name: Ident, path: &hir::Expr) -> bool {
+    if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.node {
+        path.segments.len() == 1 && path.segments[0].ident == name
     } else {
-        None
+        false
     }
 }
 
-fn only_derefs(cx: &LateContext<'_, '_>, expr: &Expr, id: ast::Ident) -> bool {
-    match expr.node {
-        ExprKind::Unary(UnDeref, ref subexpr) if !is_adjusted(cx, subexpr) => only_derefs(cx, subexpr, id),
-        _ => expr_eq_name(cx, expr, id),
-    }
+fn lint_needless_cloning(cx: &LateContext<'_, '_>, root: Span, receiver: Span) {
+    span_lint_and_sugg(
+        cx,
+        MAP_CLONE,
+        root.trim_start(receiver).unwrap(),
+        "You are needlessly cloning iterator elements",
+        "Remove the map call",
+        String::new(),
+        Applicability::MachineApplicable,
+    )
 }
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MAP_CLONE)
+fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, copied: bool) {
+    let mut applicability = Applicability::MachineApplicable;
+    if copied {
+        span_lint_and_sugg(
+            cx,
+            MAP_CLONE,
+            replace,
+            "You are using an explicit closure for copying elements",
+            "Consider calling the dedicated `copied` method",
+            format!(
+                "{}.copied()",
+                snippet_with_applicability(cx, root, "..", &mut applicability)
+            ),
+            applicability,
+        )
+    } else {
+        span_lint_and_sugg(
+            cx,
+            MAP_CLONE,
+            replace,
+            "You are using an explicit closure for cloning elements",
+            "Consider calling the dedicated `cloned` method",
+            format!(
+                "{}.cloned()",
+                snippet_with_applicability(cx, root, "..", &mut applicability)
+            ),
+            applicability,
+        )
     }
 }
index 6ccf8daa71d64cbe7dc45b1f6463e2a37e080032..5318badf36c6313c48f8ef4ad83c3fd2f6af4de0 100644 (file)
@@ -1,93 +1,86 @@
-use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::paths;
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
 use if_chain::if_chain;
-use rustc::ty;
+use rustc::hir;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use rustc_errors::Applicability;
-use syntax::codemap::Span;
-use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
-use crate::utils::paths;
-
-#[derive(Clone)]
-pub struct Pass;
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for usage of `option.map(f)` where f is a function
-/// or closure that returns the unit type.
-///
-/// **Why is this bad?** Readability, this can be written more clearly with
-/// an if let statement
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// let x: Option<&str> = do_stuff();
-/// x.map(log_err_msg);
-/// x.map(|msg| log_err_msg(format_msg(msg)))
-/// ```
-///
-/// The correct use would be:
-///
-/// ```rust
-/// let x: Option<&str> = do_stuff();
-/// if let Some(msg) = x {
-///     log_err_msg(msg)
-/// }
-/// if let Some(msg) = x {
-///     log_err_msg(format_msg(msg))
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `option.map(f)` where f is a function
+    /// or closure that returns the unit type.
+    ///
+    /// **Why is this bad?** Readability, this can be written more clearly with
+    /// an if let statement
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x: Option<&str> = do_stuff();
+    /// x.map(log_err_msg);
+    /// x.map(|msg| log_err_msg(format_msg(msg)))
+    /// ```
+    ///
+    /// The correct use would be:
+    ///
+    /// ```rust
+    /// let x: Option<&str> = do_stuff();
+    /// if let Some(msg) = x {
+    ///     log_err_msg(msg)
+    /// }
+    /// if let Some(msg) = x {
+    ///     log_err_msg(format_msg(msg))
+    /// }
+    /// ```
     pub OPTION_MAP_UNIT_FN,
     complexity,
     "using `option.map(f)`, where f is a function or closure that returns ()"
 }
 
-/// **What it does:** Checks for usage of `result.map(f)` where f is a function
-/// or closure that returns the unit type.
-///
-/// **Why is this bad?** Readability, this can be written more clearly with
-/// an if let statement
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// let x: Result<&str, &str> = do_stuff();
-/// x.map(log_err_msg);
-/// x.map(|msg| log_err_msg(format_msg(msg)))
-/// ```
-///
-/// The correct use would be:
-///
-/// ```rust
-/// let x: Result<&str, &str> = do_stuff();
-/// if let Ok(msg) = x {
-///     log_err_msg(msg)
-/// }
-/// if let Ok(msg) = x {
-///     log_err_msg(format_msg(msg))
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `result.map(f)` where f is a function
+    /// or closure that returns the unit type.
+    ///
+    /// **Why is this bad?** Readability, this can be written more clearly with
+    /// an if let statement
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x: Result<&str, &str> = do_stuff();
+    /// x.map(log_err_msg);
+    /// x.map(|msg| log_err_msg(format_msg(msg)))
+    /// ```
+    ///
+    /// The correct use would be:
+    ///
+    /// ```rust
+    /// let x: Result<&str, &str> = do_stuff();
+    /// if let Ok(msg) = x {
+    ///     log_err_msg(msg)
+    /// }
+    /// if let Ok(msg) = x {
+    ///     log_err_msg(format_msg(msg))
+    /// }
+    /// ```
     pub RESULT_MAP_UNIT_FN,
     complexity,
     "using `result.map(f)`, where f is a function or closure that returns ()"
 }
 
+declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN)
-    }
-}
-
-fn is_unit_type(ty: ty::Ty<'_>) -> bool {
+fn is_unit_type(ty: Ty<'_>) -> bool {
     match ty.sty {
-        ty::TyTuple(slice) => slice.is_empty(),
-        ty::TyNever => true,
+        ty::Tuple(slice) => slice.is_empty(),
+        ty::Never => true,
         _ => false,
     }
 }
@@ -95,8 +88,8 @@ fn is_unit_type(ty: ty::Ty<'_>) -> bool {
 fn is_unit_function(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> bool {
     let ty = cx.tables.expr_ty(expr);
 
-    if let ty::TyFnDef(id, _) = ty.sty {
-        if let Some(fn_type) = cx.tcx.fn_sig(id).no_late_bound_regions() {
+    if let ty::FnDef(id, _) = ty.sty {
+        if let Some(fn_type) = cx.tcx.fn_sig(id).no_bound_vars() {
             return is_unit_type(fn_type.output());
         }
     }
@@ -117,8 +110,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
     }
 
     match expr.node {
-        hir::ExprKind::Call(_, _) |
-        hir::ExprKind::MethodCall(_, _, _) => {
+        hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _) => {
             // Calls can't be reduced any more
             Some(expr.span)
         },
@@ -133,9 +125,10 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
                     // If block only contains statements,
                     // reduce `{ X; }` to `X` or `X;`
                     match inner_stmt.node {
-                        hir::StmtKind::Decl(ref d, _) => Some(d.span),
-                        hir::StmtKind::Expr(ref e, _) => Some(e.span),
-                        hir::StmtKind::Semi(_, _) => Some(inner_stmt.span),
+                        hir::StmtKind::Local(ref local) => Some(local.span),
+                        hir::StmtKind::Expr(ref e) => Some(e.span),
+                        hir::StmtKind::Semi(..) => Some(inner_stmt.span),
+                        hir::StmtKind::Item(..) => None,
                     }
                 },
                 _ => {
@@ -145,7 +138,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
                     //
                     // We do not attempt to build a suggestion for those right now.
                     None
-                }
+                },
             }
         },
         _ => None,
@@ -154,7 +147,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
 
 fn unit_closure<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'a hir::Expr) -> Option<(&'tcx hir::Arg, &'a hir::Expr)> {
     if let hir::ExprKind::Closure(_, ref decl, inner_expr_id, _, _) = expr.node {
-        let body = cx.tcx.hir.body(inner_expr_id);
+        let body = cx.tcx.hir().body(inner_expr_id);
         let body_expr = &body.value;
 
         if_chain! {
@@ -169,7 +162,7 @@ fn unit_closure<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'a hir::Expr) -> Op
     None
 }
 
-/// Builds a name for the let binding variable (var_arg)
+/// Builds a name for the let binding variable (`var_arg`)
 ///
 /// `x.field` => `x_field`
 /// `y` => `_y`
@@ -179,81 +172,82 @@ fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String {
     match &var_arg.node {
         hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
         hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
-        _ => "_".to_string()
+        _ => "_".to_string(),
     }
 }
 
 fn suggestion_msg(function_type: &str, map_type: &str) -> String {
     format!(
         "called `map(f)` on an {0} value where `f` is a unit {1}",
-        map_type,
-        function_type
+        map_type, function_type
     )
 }
 
 fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr, map_args: &[hir::Expr]) {
     let var_arg = &map_args[0];
-    let fn_arg = &map_args[1];
 
-    let (map_type, variant, lint) =
-        if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
-            ("Option", "Some", OPTION_MAP_UNIT_FN)
-        } else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
-            ("Result", "Ok", RESULT_MAP_UNIT_FN)
-        } else {
-            return
-        };
+    let (map_type, variant, lint) = if match_type(cx, cx.tables.expr_ty(var_arg), &*paths::OPTION) {
+        ("Option", "Some", OPTION_MAP_UNIT_FN)
+    } else if match_type(cx, cx.tables.expr_ty(var_arg), &*paths::RESULT) {
+        ("Result", "Ok", RESULT_MAP_UNIT_FN)
+    } else {
+        return;
+    };
+    let fn_arg = &map_args[1];
 
     if is_unit_function(cx, fn_arg) {
         let msg = suggestion_msg("function", map_type);
-        let suggestion = format!("if let {0}({1}) = {2} {{ {3}(...) }}",
-                                 variant,
-                                 let_binding_name(cx, var_arg),
-                                 snippet(cx, var_arg.span, "_"),
-                                 snippet(cx, fn_arg.span, "_"));
+        let suggestion = format!(
+            "if let {0}({1}) = {2} {{ {3}(...) }}",
+            variant,
+            let_binding_name(cx, var_arg),
+            snippet(cx, var_arg.span, "_"),
+            snippet(cx, fn_arg.span, "_")
+        );
 
         span_lint_and_then(cx, lint, expr.span, &msg, |db| {
-            db.span_suggestion_with_applicability(stmt.span,
-                                                  "try this",
-                                                  suggestion,
-                                                  Applicability::Unspecified);
+            db.span_suggestion(stmt.span, "try this", suggestion, Applicability::Unspecified);
         });
     } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
         let msg = suggestion_msg("closure", map_type);
 
         span_lint_and_then(cx, lint, expr.span, &msg, |db| {
             if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
-                let suggestion = format!("if let {0}({1}) = {2} {{ {3} }}",
-                                         variant,
-                                         snippet(cx, binding.pat.span, "_"),
-                                         snippet(cx, var_arg.span, "_"),
-                                         snippet(cx, reduced_expr_span, "_"));
-                db.span_suggestion(stmt.span, "try this", suggestion);
+                let suggestion = format!(
+                    "if let {0}({1}) = {2} {{ {3} }}",
+                    variant,
+                    snippet(cx, binding.pat.span, "_"),
+                    snippet(cx, var_arg.span, "_"),
+                    snippet(cx, reduced_expr_span, "_")
+                );
+                db.span_suggestion(
+                    stmt.span,
+                    "try this",
+                    suggestion,
+                    Applicability::MachineApplicable, // snippet
+                );
             } else {
-                let suggestion = format!("if let {0}({1}) = {2} {{ ... }}",
-                                         variant,
-                                         snippet(cx, binding.pat.span, "_"),
-                                         snippet(cx, var_arg.span, "_"));
-                db.span_suggestion_with_applicability(stmt.span,
-                                                      "try this",
-                                                      suggestion,
-                                                      Applicability::Unspecified);
+                let suggestion = format!(
+                    "if let {0}({1}) = {2} {{ ... }}",
+                    variant,
+                    snippet(cx, binding.pat.span, "_"),
+                    snippet(cx, var_arg.span, "_")
+                );
+                db.span_suggestion(stmt.span, "try this", suggestion, Applicability::Unspecified);
             }
         });
     }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &hir::Stmt) {
-        if in_macro(stmt.span) {
+        if in_macro_or_desugar(stmt.span) {
             return;
         }
 
-        if let hir::StmtKind::Semi(ref expr, _) = stmt.node {
-            if let hir::ExprKind::MethodCall(_, _, _) = expr.node {
-                if let Some(arglists) = method_chain_args(expr, &["map"]) {
-                    lint_map_unit_fn(cx, stmt, expr, arglists[0]);
-                }
+        if let hir::StmtKind::Semi(ref expr) = stmt.node {
+            if let Some(arglists) = method_chain_args(expr, &[*sym::map]) {
+                lint_map_unit_fn(cx, stmt, expr, arglists[0]);
             }
         }
     }
index 6bdcd004134eb97a37c8458abeb73a2e0bf68d21..fb290ee3ac80ed5bc99d932b0798b1b9f148e9ec 100644 (file)
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::consts::{constant, Constant};
+use crate::utils::paths;
+use crate::utils::sugg::Sugg;
+use crate::utils::sym;
+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,
+};
 use if_chain::if_chain;
+use rustc::hir::def::CtorKind;
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use std::cmp::Ordering;
 use std::collections::Bound;
+use std::ops::Deref;
 use syntax::ast::LitKind;
-use syntax::codemap::Span;
-use crate::utils::paths;
-use crate::utils::{expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg,
-            remove_blocks, snippet, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty};
-use crate::utils::sugg::Sugg;
-use crate::consts::{constant, Constant};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for matches with a single arm where an `if let`
-/// will usually suffice.
-///
-/// **Why is this bad?** Just readability – `if let` nests less than a `match`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// match x {
-///     Some(ref foo) => bar(foo),
-///     _ => ()
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches with a single arm where an `if let`
+    /// will usually suffice.
+    ///
+    /// **Why is this bad?** Just readability – `if let` nests less than a `match`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # fn bar(stool: &str) {}
+    /// # let x = Some("abc");
+    /// match x {
+    ///     Some(ref foo) => bar(foo),
+    ///     _ => (),
+    /// }
+    /// ```
     pub SINGLE_MATCH,
     style,
-    "a match statement with a single nontrivial arm (i.e. where the other arm \
-     is `_ => {}`) instead of `if let`"
+    "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
 }
 
-/// **What it does:** Checks for matches with a two arms where an `if let` will
-/// usually suffice.
-///
-/// **Why is this bad?** Just readability – `if let` nests less than a `match`.
-///
-/// **Known problems:** Personal style preferences may differ.
-///
-/// **Example:**
-/// ```rust
-/// match x {
-///     Some(ref foo) => bar(foo),
-///     _ => bar(other_ref),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches with a two arms where an `if let else` will
+    /// usually suffice.
+    ///
+    /// **Why is this bad?** Just readability – `if let` nests less than a `match`.
+    ///
+    /// **Known problems:** Personal style preferences may differ.
+    ///
+    /// **Example:**
+    ///
+    /// Using `match`:
+    ///
+    /// ```rust
+    /// match x {
+    ///     Some(ref foo) => bar(foo),
+    ///     _ => bar(other_ref),
+    /// }
+    /// ```
+    ///
+    /// Using `if let` with `else`:
+    ///
+    /// ```rust
+    /// if let Some(ref foo) = x {
+    ///     bar(foo);
+    /// } else {
+    ///     bar(other_ref);
+    /// }
+    /// ```
     pub SINGLE_MATCH_ELSE,
     pedantic,
-    "a match statement with a two arms where the second arm's pattern is a wildcard \
-     instead of `if let`"
+    "a match statement with a two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
 }
 
-/// **What it does:** Checks for matches where all arms match a reference,
-/// suggesting to remove the reference and deref the matched expression
-/// instead. It also checks for `if let &foo = bar` blocks.
-///
-/// **Why is this bad?** It just makes the code less readable. That reference
-/// destructuring adds nothing to the code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// match x {
-///     &A(ref y) => foo(y),
-///     &B => bar(),
-///     _ => frob(&x),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches where all arms match a reference,
+    /// suggesting to remove the reference and deref the matched expression
+    /// instead. It also checks for `if let &foo = bar` blocks.
+    ///
+    /// **Why is this bad?** It just makes the code less readable. That reference
+    /// destructuring adds nothing to the code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// match x {
+    ///     &A(ref y) => foo(y),
+    ///     &B => bar(),
+    ///     _ => frob(&x),
+    /// }
+    /// ```
     pub MATCH_REF_PATS,
     style,
     "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
 }
 
-/// **What it does:** Checks for matches where match expression is a `bool`. It
-/// suggests to replace the expression with an `if...else` block.
-///
-/// **Why is this bad?** It makes the code less readable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let condition: bool = true;
-/// match condition {
-///     true => foo(),
-///     false => bar(),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches where match expression is a `bool`. It
+    /// suggests to replace the expression with an `if...else` block.
+    ///
+    /// **Why is this bad?** It makes the code less readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # fn foo() {}
+    /// # fn bar() {}
+    /// let condition: bool = true;
+    /// match condition {
+    ///     true => foo(),
+    ///     false => bar(),
+    /// }
+    /// ```
+    /// Use if/else instead:
+    /// ```rust
+    /// # fn foo() {}
+    /// # fn bar() {}
+    /// let condition: bool = true;
+    /// if condition {
+    ///     foo();
+    /// } else {
+    ///     bar();
+    /// }
+    /// ```
     pub MATCH_BOOL,
     style,
     "a match on a boolean expression instead of an `if..else` block"
 }
 
-/// **What it does:** Checks for overlapping match arms.
-///
-/// **Why is this bad?** It is likely to be an error and if not, makes the code
-/// less obvious.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = 5;
-/// match x {
-///     1 ... 10 => println!("1 ... 10"),
-///     5 ... 15 => println!("5 ... 15"),
-///     _ => (),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for overlapping match arms.
+    ///
+    /// **Why is this bad?** It is likely to be an error and if not, makes the code
+    /// less obvious.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = 5;
+    /// match x {
+    ///     1...10 => println!("1 ... 10"),
+    ///     5...15 => println!("5 ... 15"),
+    ///     _ => (),
+    /// }
+    /// ```
     pub MATCH_OVERLAPPING_ARM,
     style,
     "a match with overlapping arms"
 }
 
-/// **What it does:** Checks for arm which matches all errors with `Err(_)`
-/// and take drastic actions like `panic!`.
-///
-/// **Why is this bad?** It is generally a bad practice, just like
-/// catching all exceptions in java with `catch(Exception)`
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x : Result(i32, &str) = Ok(3);
-/// match x {
-///     Ok(_) => println!("ok"),
-///     Err(_) => panic!("err"),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for arm which matches all errors with `Err(_)`
+    /// and take drastic actions like `panic!`.
+    ///
+    /// **Why is this bad?** It is generally a bad practice, just like
+    /// catching all exceptions in java with `catch(Exception)`
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: Result<i32, &str> = Ok(3);
+    /// match x {
+    ///     Ok(_) => println!("ok"),
+    ///     Err(_) => panic!("err"),
+    /// }
+    /// ```
     pub MATCH_WILD_ERR_ARM,
     style,
     "a match with `Err(_)` arm and take drastic actions"
 }
 
-/// **What it does:** Checks for match which is used to add a reference to an
-/// `Option` value.
-///
-/// **Why is this bad?** Using `as_ref()` or `as_mut()` instead is shorter.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x: Option<()> = None;
-/// let r: Option<&()> = match x {
-///   None => None,
-///   Some(ref v) => Some(v),
-/// };
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for match which is used to add a reference to an
+    /// `Option` value.
+    ///
+    /// **Why is this bad?** Using `as_ref()` or `as_mut()` instead is shorter.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: Option<()> = None;
+    /// let r: Option<&()> = match x {
+    ///     None => None,
+    ///     Some(ref v) => Some(v),
+    /// };
+    /// ```
     pub MATCH_AS_REF,
     complexity,
     "a match on an Option value instead of using `as_ref()` or `as_mut`"
 }
 
-#[allow(missing_copy_implementations)]
-pub struct MatchPass;
-
-impl LintPass for MatchPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            SINGLE_MATCH,
-            MATCH_REF_PATS,
-            MATCH_BOOL,
-            SINGLE_MATCH_ELSE,
-            MATCH_OVERLAPPING_ARM,
-            MATCH_WILD_ERR_ARM,
-            MATCH_AS_REF
-        )
-    }
+declare_clippy_lint! {
+    /// **What it does:** Checks for wildcard enum matches using `_`.
+    ///
+    /// **Why is this bad?** New enum variants added by library updates can be missed.
+    ///
+    /// **Known problems:** Suggested replacements may be incorrect if guards exhaustively cover some
+    /// variants, and also may not use correct path to enum if it's not present in the current scope.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// match x {
+    ///     A => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    pub WILDCARD_ENUM_MATCH_ARM,
+    restriction,
+    "a wildcard enum match arm using `_`"
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass {
+declare_lint_pass!(Matches => [
+    SINGLE_MATCH,
+    MATCH_REF_PATS,
+    MATCH_BOOL,
+    SINGLE_MATCH_ELSE,
+    MATCH_OVERLAPPING_ARM,
+    MATCH_WILD_ERR_ARM,
+    MATCH_AS_REF,
+    WILDCARD_ENUM_MATCH_ARM
+]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if in_external_macro(cx.sess(), expr.span) {
             return;
@@ -191,6 +237,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             check_match_bool(cx, ex, arms, expr);
             check_overlapping_arms(cx, ex, arms);
             check_wild_err_arm(cx, ex, arms);
+            check_wild_enum_match(cx, ex, arms);
             check_match_as_ref(cx, ex, arms, expr);
         }
         if let ExprKind::Match(ref ex, ref arms, _) = expr.node {
@@ -199,7 +246,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
     if arms.len() == 2 &&
       arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
@@ -215,26 +262,36 @@ fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
             return;
         };
         let ty = cx.tables.expr_ty(ex);
-        if ty.sty != ty::TyBool || is_allowed(cx, MATCH_BOOL, ex.id) {
+        if ty.sty != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
             check_single_match_single_pattern(cx, ex, arms, expr, els);
             check_single_match_opt_like(cx, ex, arms, expr, ty, els);
         }
     }
 }
 
-fn check_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
+fn check_single_match_single_pattern(
+    cx: &LateContext<'_, '_>,
+    ex: &Expr,
+    arms: &[Arm],
+    expr: &Expr,
+    els: Option<&Expr>,
+) {
     if is_wild(&arms[1].pats[0]) {
         report_single_match_single_pattern(cx, ex, arms, expr, els);
     }
 }
 
-fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
-    let lint = if els.is_some() {
-        SINGLE_MATCH_ELSE
-    } else {
-        SINGLE_MATCH
-    };
-    let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
+fn report_single_match_single_pattern(
+    cx: &LateContext<'_, '_>,
+    ex: &Expr,
+    arms: &[Arm],
+    expr: &Expr,
+    els: Option<&Expr>,
+) {
+    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
+    let els_str = els.map_or(String::new(), |els| {
+        format!(" else {}", expr_block(cx, els, None, ".."))
+    });
     span_lint_and_sugg(
         cx,
         lint,
@@ -247,32 +304,40 @@ fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms:
             snippet(cx, arms[0].pats[0].span, ".."),
             snippet(cx, ex.span, ".."),
             expr_block(cx, &arms[0].body, None, ".."),
-            els_str
+            els_str,
         ),
+        Applicability::HasPlaceholders,
     );
 }
 
-fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty<'_>, els: Option<&Expr>) {
-    // list of candidate Enums we know will never get any more members
+fn check_single_match_opt_like(
+    cx: &LateContext<'_, '_>,
+    ex: &Expr,
+    arms: &[Arm],
+    expr: &Expr,
+    ty: Ty<'_>,
+    els: Option<&Expr>,
+) {
+    // list of candidate `Enum`s we know will never get any more members
     let candidates = &[
-        (&paths::COW, "Borrowed"),
-        (&paths::COW, "Cow::Borrowed"),
-        (&paths::COW, "Cow::Owned"),
-        (&paths::COW, "Owned"),
-        (&paths::OPTION, "None"),
-        (&paths::RESULT, "Err"),
-        (&paths::RESULT, "Ok"),
+        (&*paths::COW, "Borrowed"),
+        (&*paths::COW, "Cow::Borrowed"),
+        (&*paths::COW, "Cow::Owned"),
+        (&*paths::COW, "Owned"),
+        (&*paths::OPTION, "None"),
+        (&*paths::RESULT, "Err"),
+        (&*paths::RESULT, "Ok"),
     ];
 
     let path = match arms[1].pats[0].node {
         PatKind::TupleStruct(ref path, ref inner, _) => {
-            // contains any non wildcard patterns? e.g. Err(err)
+            // Contains any non wildcard patterns (e.g., `Err(err)`)?
             if !inner.iter().all(is_wild) {
                 return;
             }
             print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))
         },
-        PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None) => ident.to_string(),
+        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
         PatKind::Path(ref path) => print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
         _ => return,
     };
@@ -285,8 +350,8 @@ fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]
 }
 
 fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
-    // type of expression == bool
-    if cx.tables.expr_ty(ex).sty == ty::TyBool {
+    // Type of expression is `bool`.
+    if cx.tables.expr_ty(ex).sty == ty::Bool {
         span_lint_and_then(
             cx,
             MATCH_BOOL,
@@ -330,7 +395,12 @@ fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Ex
                         };
 
                         if let Some(sugg) = sugg {
-                            db.span_suggestion(expr.span, "consider using an if/else expression", sugg);
+                            db.span_suggestion(
+                                expr.span,
+                                "consider using an if/else expression",
+                                sugg,
+                                Applicability::HasPlaceholders,
+                            );
                         }
                     }
                 }
@@ -367,7 +437,7 @@ fn is_wild(pat: &impl std::ops::Deref<Target = Pat>) -> bool {
 
 fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
     let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex));
-    if match_type(cx, ex_ty, &paths::RESULT) {
+    if match_type(cx, ex_ty, &*paths::RESULT) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pats[0].node {
                 let path_str = print::to_string(print::NO_ANN, |s| s.print_qpath(path, false));
@@ -392,14 +462,101 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
     }
 }
 
+fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
+    let ty = cx.tables.expr_ty(ex);
+    if !ty.is_enum() {
+        // If there isn't a nice closed set of possible values that can be conveniently enumerated,
+        // don't complain about not enumerating the mall.
+        return;
+    }
+
+    // First pass - check for violation, but don't do much book-keeping because this is hopefully
+    // the uncommon case, and the book-keeping is slightly expensive.
+    let mut wildcard_span = None;
+    let mut wildcard_ident = None;
+    for arm in arms {
+        for pat in &arm.pats {
+            if let PatKind::Wild = pat.node {
+                wildcard_span = Some(pat.span);
+            } else if let PatKind::Binding(_, _, ident, None) = pat.node {
+                wildcard_span = Some(pat.span);
+                wildcard_ident = Some(ident);
+            }
+        }
+    }
+
+    if let Some(wildcard_span) = wildcard_span {
+        // Accumulate the variants which should be put in place of the wildcard because they're not
+        // already covered.
+
+        let mut missing_variants = vec![];
+        if let ty::Adt(def, _) = ty.sty {
+            for variant in &def.variants {
+                missing_variants.push(variant);
+            }
+        }
+
+        for arm in arms {
+            if arm.guard.is_some() {
+                // Guards mean that this case probably isn't exhaustively covered. Technically
+                // this is incorrect, as we should really check whether each variant is exhaustively
+                // covered by the set of guards that cover it, but that's really hard to do.
+                continue;
+            }
+            for pat in &arm.pats {
+                if let PatKind::Path(ref path) = pat.deref().node {
+                    if let QPath::Resolved(_, p) = path {
+                        missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
+                    }
+                } else if let PatKind::TupleStruct(ref path, ..) = pat.deref().node {
+                    if let QPath::Resolved(_, p) = path {
+                        missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
+                    }
+                }
+            }
+        }
+
+        let suggestion: Vec<String> = missing_variants
+            .iter()
+            .map(|v| {
+                let suffix = match v.ctor_kind {
+                    CtorKind::Fn => "(..)",
+                    CtorKind::Const | CtorKind::Fictive => "",
+                };
+                let ident_str = if let Some(ident) = wildcard_ident {
+                    format!("{} @ ", ident.name)
+                } else {
+                    String::new()
+                };
+                // This path assumes that the enum type is imported into scope.
+                format!("{}{}{}", ident_str, cx.tcx.def_path_str(v.def_id), suffix)
+            })
+            .collect();
+
+        if suggestion.is_empty() {
+            return;
+        }
+
+        span_lint_and_sugg(
+            cx,
+            WILDCARD_ENUM_MATCH_ARM,
+            wildcard_span,
+            "wildcard match will miss any future added variants.",
+            "try this",
+            suggestion.join(" | "),
+            Applicability::MachineApplicable,
+        )
+    }
+}
+
 // If the block contains only a `panic!` macro (as expression or statement)
 fn is_panic_block(block: &Block) -> bool {
     match (&block.expr, block.stmts.len(), block.stmts.first()) {
         (&Some(ref exp), 0, _) => {
-            is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none()
+            is_expn_of(exp.span, *sym::panic).is_some() && is_expn_of(exp.span, *sym::unreachable).is_none()
         },
         (&None, 1, Some(stmt)) => {
-            is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
+            is_expn_of(stmt.span, *sym::panic).is_some() && is_expn_of(stmt.span, *sym::unreachable).is_none()
         },
         _ => false,
     }
@@ -409,13 +566,15 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
     if has_only_ref_pats(arms) {
         let mut suggs = Vec::new();
         let (title, msg) = if let ExprKind::AddrOf(Mutability::MutImmutable, ref inner) = ex.node {
-            suggs.push((ex.span, Sugg::hir(cx, inner, "..").to_string()));
+            let span = ex.span.source_callsite();
+            suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
             (
                 "you don't need to add `&` to both the expression and the patterns",
                 "try",
             )
         } else {
-            suggs.push((ex.span, Sugg::hir(cx, ex, "..").deref().to_string()));
+            let span = ex.span.source_callsite();
+            suggs.push((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
             (
                 "you don't need to add `&` to all patterns",
                 "instead of prefixing all patterns with `&`, you can dereference the expression",
@@ -431,15 +590,20 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
         }));
 
         span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |db| {
-            multispan_sugg(db, msg.to_owned(), suggs);
+            if !in_macro_or_desugar(expr.span) {
+                multispan_sugg(db, msg.to_owned(), suggs);
+            }
         });
     }
 }
 
 fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
-    if arms.len() == 2 &&
-        arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
-        arms[1].pats.len() == 1 && arms[1].guard.is_none() {
+    if arms.len() == 2
+        && arms[0].pats.len() == 1
+        && arms[0].guard.is_none()
+        && arms[1].pats.len() == 1
+        && arms[1].guard.is_none()
+    {
         let arm_ref: Option<BindingAnnotation> = if is_none_arm(&arms[0]) {
             is_ref_some_arm(&arms[1])
         } else if is_none_arm(&arms[1]) {
@@ -448,36 +612,42 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
             None
         };
         if let Some(rb) = arm_ref {
-            let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" };
+            let suggestion = if rb == BindingAnnotation::Ref {
+                "as_ref"
+            } else {
+                "as_mut"
+            };
+            let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
                 MATCH_AS_REF,
                 expr.span,
                 &format!("use {}() instead", suggestion),
                 "try this",
-                format!("{}.{}()", snippet(cx, ex.span, "_"), suggestion)
+                format!(
+                    "{}.{}()",
+                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
+                    suggestion
+                ),
+                applicability,
             )
         }
     }
 }
 
-/// Get all arms that are unbounded `PatRange`s.
-fn all_ranges<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    arms: &'tcx [Arm],
-) -> Vec<SpannedRange<Constant>> {
+/// Gets all arms that are unbounded `PatRange`s.
+fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> {
     arms.iter()
         .flat_map(|arm| {
             if let Arm {
-                ref pats,
-                guard: None,
-                ..
+                ref pats, guard: None, ..
             } = *arm
             {
                 pats.iter()
             } else {
                 [].iter()
-            }.filter_map(|pat| {
+            }
+            .filter_map(|pat| {
                 if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node {
                     let lhs = constant(cx, cx.tables, lhs)?.0;
                     let rhs = constant(cx, cx.tables, rhs)?.0;
@@ -485,12 +655,18 @@ fn all_ranges<'a, 'tcx>(
                         RangeEnd::Included => Bound::Included(rhs),
                         RangeEnd::Excluded => Bound::Excluded(rhs),
                     };
-                    return Some(SpannedRange { span: pat.span, node: (lhs, rhs) });
+                    return Some(SpannedRange {
+                        span: pat.span,
+                        node: (lhs, rhs),
+                    });
                 }
 
                 if let PatKind::Lit(ref value) = pat.node {
                     let value = constant(cx, cx.tables, value)?.0;
-                    return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) });
+                    return Some(SpannedRange {
+                        span: pat.span,
+                        node: (value.clone(), Bound::Included(value)),
+                    });
                 }
 
                 None
@@ -507,31 +683,22 @@ pub struct SpannedRange<T> {
 
 type TypedRanges = Vec<SpannedRange<u128>>;
 
-/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
+/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
 /// and other types than
 /// `Uint` and `Int` probably don't make sense.
 fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
     ranges
         .iter()
         .filter_map(|range| match range.node {
-            (
-                Constant::Int(start),
-                Bound::Included(Constant::Int(end)),
-            ) => Some(SpannedRange {
+            (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
                 span: range.span,
                 node: (start, Bound::Included(end)),
             }),
-            (
-                Constant::Int(start),
-                Bound::Excluded(Constant::Int(end)),
-            ) => Some(SpannedRange {
+            (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
                 span: range.span,
                 node: (start, Bound::Excluded(end)),
             }),
-            (
-                Constant::Int(start),
-                Bound::Unbounded,
-            ) => Some(SpannedRange {
+            (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
                 span: range.span,
                 node: (start, Bound::Unbounded),
             }),
@@ -551,7 +718,7 @@ fn is_unit_expr(expr: &Expr) -> bool {
 // Checks if arm has the form `None => None`
 fn is_none_arm(arm: &Arm) -> bool {
     match arm.pats[0].node {
-        PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => true,
+        PatKind::Path(ref path) if match_qpath(path, &*paths::OPTION_NONE) => true,
         _ => false,
     }
 }
@@ -560,12 +727,12 @@ fn is_none_arm(arm: &Arm) -> bool {
 fn is_ref_some_arm(arm: &Arm) -> Option<BindingAnnotation> {
     if_chain! {
         if let PatKind::TupleStruct(ref path, ref pats, _) = arm.pats[0].node;
-        if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME);
-        if let PatKind::Binding(rb, _, ident, _) = pats[0].node;
+        if pats.len() == 1 && match_qpath(path, &*paths::OPTION_SOME);
+        if let PatKind::Binding(rb, .., ident, _) = pats[0].node;
         if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
         if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).node;
         if let ExprKind::Path(ref some_path) = e.node;
-        if match_qpath(some_path, &paths::OPTION_SOME) && args.len() == 1;
+        if match_qpath(some_path, &*paths::OPTION_SOME) && args.len() == 1;
         if let ExprKind::Path(ref qpath) = args[0].node;
         if let &QPath::Resolved(_, ref path2) = qpath;
         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
@@ -577,7 +744,8 @@ fn is_ref_some_arm(arm: &Arm) -> Option<BindingAnnotation> {
 }
 
 fn has_only_ref_pats(arms: &[Arm]) -> bool {
-    let mapped = arms.iter()
+    let mapped = arms
+        .iter()
         .flat_map(|a| &a.pats)
         .map(|p| {
             match p.node {
@@ -651,8 +819,10 @@ fn cmp(&self, other: &Self) -> Ordering {
 
     for (a, b) in values.iter().zip(values.iter().skip(1)) {
         match (a, b) {
-            (&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node {
-                return Some((ra, rb));
+            (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
+                if ra.node != rb.node {
+                    return Some((ra, rb));
+                }
             },
             (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
             _ => return Some((a.range(), b.range())),
diff --git a/clippy_lints/src/mem_discriminant.rs b/clippy_lints/src/mem_discriminant.rs
new file mode 100644 (file)
index 0000000..2ce5664
--- /dev/null
@@ -0,0 +1,81 @@
+use crate::utils::{match_def_path, paths, snippet, span_lint_and_then, walk_ptrs_ty_depth};
+use if_chain::if_chain;
+use rustc::hir::{Expr, ExprKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+
+use std::iter;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
+    ///
+    /// **Why is this bad?** The value of `mem::discriminant()` on non-enum types
+    /// is unspecified.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::mem;
+    ///
+    /// mem::discriminant(&"hello");
+    /// mem::discriminant(&&Some(2));
+    /// ```
+    pub MEM_DISCRIMINANT_NON_ENUM,
+    correctness,
+    "calling mem::descriminant on non-enum type"
+}
+
+declare_lint_pass!(MemDiscriminant => [MEM_DISCRIMINANT_NON_ENUM]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemDiscriminant {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if_chain! {
+            if let ExprKind::Call(ref func, ref func_args) = expr.node;
+            // is `mem::discriminant`
+            if let ExprKind::Path(ref func_qpath) = func.node;
+            if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &*paths::MEM_DISCRIMINANT);
+            // type is non-enum
+            let ty_param = cx.tables.node_substs(func.hir_id).type_at(0);
+            if !ty_param.is_enum();
+
+            then {
+                span_lint_and_then(
+                    cx,
+                    MEM_DISCRIMINANT_NON_ENUM,
+                    expr.span,
+                    &format!("calling `mem::discriminant` on non-enum type `{}`", ty_param),
+                    |db| {
+                        // if this is a reference to an enum, suggest dereferencing
+                        let (base_ty, ptr_depth) = walk_ptrs_ty_depth(ty_param);
+                        if ptr_depth >= 1 && base_ty.is_enum() {
+                            let param = &func_args[0];
+
+                            // cancel out '&'s first
+                            let mut derefs_needed = ptr_depth;
+                            let mut cur_expr = param;
+                            while derefs_needed > 0  {
+                                if let ExprKind::AddrOf(_, ref inner_expr) = cur_expr.node {
+                                    derefs_needed -= 1;
+                                    cur_expr = inner_expr;
+                                } else {
+                                    break;
+                                }
+                            }
+
+                            let derefs: String = iter::repeat('*').take(derefs_needed).collect();
+                            db.span_suggestion(
+                                param.span,
+                                "try dereferencing",
+                                format!("{}{}", derefs, snippet(cx, cur_expr.span, "<param>")),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    },
+                )
+            }
+        }
+    }
+}
index 88c2445864686c080bbaad9cfe548f1f05c11831..3f314d332823e468488677b55a77d23613864e5b 100644 (file)
@@ -1,46 +1,37 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{match_def_path, paths, span_lint};
 use rustc::hir::{Expr, ExprKind};
-use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
-/// `Drop`.
-///
-/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its
-/// destructor, possibly causing leaks.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// mem::forget(Rc::new(55)))
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
+    /// `Drop`.
+    ///
+    /// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its
+    /// destructor, possibly causing leaks.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// mem::forget(Rc::new(55))
+    /// ```
     pub MEM_FORGET,
     restriction,
     "`mem::forget` usage on `Drop` types, likely to cause memory leaks"
 }
 
-pub struct MemForget;
-
-impl LintPass for MemForget {
-    fn get_lints(&self) -> LintArray {
-        lint_array![MEM_FORGET]
-    }
-}
+declare_lint_pass!(MemForget => [MEM_FORGET]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
         if let ExprKind::Call(ref path_expr, ref args) = e.node {
             if let ExprKind::Path(ref qpath) = path_expr.node {
-                if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path_expr.hir_id)) {
-                    if match_def_path(cx.tcx, def_id, &paths::MEM_FORGET) {
+                if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
+                    if match_def_path(cx, def_id, &*paths::MEM_FORGET) {
                         let forgot_ty = cx.tables.expr_ty(&args[0]);
 
-                        if match forgot_ty.ty_adt_def() {
-                            Some(def) => def.has_dtor(cx.tcx),
-                            _ => false,
-                        } {
+                        if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
                             span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type");
                         }
                     }
diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs
new file mode 100644 (file)
index 0000000..2649fd6
--- /dev/null
@@ -0,0 +1,82 @@
+use crate::utils::{match_def_path, match_qpath, paths, snippet_with_applicability, span_lint_and_sugg};
+use if_chain::if_chain;
+use rustc::hir::{Expr, ExprKind, MutMutable, QPath};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `mem::replace()` on an `Option` with
+    /// `None`.
+    ///
+    /// **Why is this bad?** `Option` already has the method `take()` for
+    /// taking its current value (Some(..) or None) and replacing it with
+    /// `None`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::mem;
+    ///
+    /// let mut an_option = Some(0);
+    /// let replaced = mem::replace(&mut an_option, None);
+    /// ```
+    /// Is better expressed with:
+    /// ```rust
+    /// let mut an_option = Some(0);
+    /// let taken = an_option.take();
+    /// ```
+    pub MEM_REPLACE_OPTION_WITH_NONE,
+    style,
+    "replacing an `Option` with `None` instead of `take()`"
+}
+
+declare_lint_pass!(MemReplace => [MEM_REPLACE_OPTION_WITH_NONE]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if_chain! {
+            // Check that `expr` is a call to `mem::replace()`
+            if let ExprKind::Call(ref func, ref func_args) = expr.node;
+            if func_args.len() == 2;
+            if let ExprKind::Path(ref func_qpath) = func.node;
+            if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &*paths::MEM_REPLACE);
+
+            // Check that second argument is `Option::None`
+            if let ExprKind::Path(ref replacement_qpath) = func_args[1].node;
+            if match_qpath(replacement_qpath, &*paths::OPTION_NONE);
+
+            then {
+                // Since this is a late pass (already type-checked),
+                // and we already know that the second argument is an
+                // `Option`, we do not need to check the first
+                // argument's type. All that's left is to get
+                // replacee's path.
+                let replaced_path = match func_args[0].node {
+                    ExprKind::AddrOf(MutMutable, ref replaced) => {
+                        if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.node {
+                            replaced_path
+                        } else {
+                            return
+                        }
+                    },
+                    ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path,
+                    _ => return,
+                };
+
+                let mut applicability = Applicability::MachineApplicable;
+                span_lint_and_sugg(
+                    cx,
+                    MEM_REPLACE_OPTION_WITH_NONE,
+                    expr.span,
+                    "replacing an `Option` with `None`",
+                    "consider `Option::take()` instead",
+                    format!("{}.take()", snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)),
+                    applicability,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs
deleted file mode 100644 (file)
index 33c532e..0000000
+++ /dev/null
@@ -1,2198 +0,0 @@
-use matches::matches;
-use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use rustc::ty::{self, Ty};
-use rustc::hir::def::Def;
-use std::borrow::Cow;
-use std::fmt;
-use std::iter;
-use syntax::ast;
-use syntax::codemap::{Span, BytePos};
-use crate::utils::{get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self,
-            is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method,
-            match_type, method_chain_args, match_var, return_ty, remove_blocks, same_tys, single_segment_path, snippet,
-            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;
-use crate::utils::sugg;
-use crate::consts::{constant, Constant};
-
-#[derive(Clone)]
-pub struct Pass;
-
-/// **What it does:** Checks for `.unwrap()` calls on `Option`s.
-///
-/// **Why is this bad?** Usually it is better to handle the `None` case, or to
-/// at least call `.expect(_)` with a more helpful message. Still, for a lot of
-/// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
-/// `Allow` by default.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x.unwrap()
-/// ```
-declare_clippy_lint! {
-    pub OPTION_UNWRAP_USED,
-    restriction,
-    "using `Option.unwrap()`, which should at least get a better message using `expect()`"
-}
-
-/// **What it does:** Checks for `.unwrap()` calls on `Result`s.
-///
-/// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err`
-/// values. Normally, you want to implement more sophisticated error handling,
-/// and propagate errors upwards with `try!`.
-///
-/// Even if you want to panic on errors, not all `Error`s implement good
-/// messages on display.  Therefore it may be beneficial to look at the places
-/// where they may get displayed. Activate this lint to do just that.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x.unwrap()
-/// ```
-declare_clippy_lint! {
-    pub RESULT_UNWRAP_USED,
-    restriction,
-    "using `Result.unwrap()`, which might be better handled"
-}
-
-/// **What it does:** Checks for methods that should live in a trait
-/// implementation of a `std` trait (see [llogiq's blog
-/// post](http://llogiq.github.io/2015/07/30/traits.html) for further
-/// information) instead of an inherent implementation.
-///
-/// **Why is this bad?** Implementing the traits improve ergonomics for users of
-/// the code, often with very little cost. Also people seeing a `mul(...)`
-/// method
-/// may expect `*` to work equally, so you should have good reason to disappoint
-/// them.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct X;
-/// impl X {
-///    fn add(&self, other: &X) -> X { .. }
-/// }
-/// ```
-declare_clippy_lint! {
-    pub SHOULD_IMPLEMENT_TRAIT,
-    style,
-    "defining a method that should be implementing a std trait"
-}
-
-/// **What it does:** Checks for methods with certain name prefixes and which
-/// doesn't match how self is taken. The actual rules are:
-///
-/// |Prefix |`self` taken          |
-/// |-------|----------------------|
-/// |`as_`  |`&self` or `&mut self`|
-/// |`from_`| none                 |
-/// |`into_`|`self`                |
-/// |`is_`  |`&self` or none       |
-/// |`to_`  |`&self`               |
-///
-/// **Why is this bad?** Consistency breeds readability. If you follow the
-/// conventions, your users won't be surprised that they, e.g., need to supply a
-/// mutable reference to a `as_..` function.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// impl X {
-///     fn as_str(self) -> &str { .. }
-/// }
-/// ```
-declare_clippy_lint! {
-    pub WRONG_SELF_CONVENTION,
-    style,
-    "defining a method named with an established prefix (like \"into_\") that takes \
-     `self` with the wrong convention"
-}
-
-/// **What it does:** This is the same as
-/// [`wrong_self_convention`](#wrong_self_convention), but for public items.
-///
-/// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
-///
-/// **Known problems:** Actually *renaming* the function may break clients if
-/// the function is part of the public interface. In that case, be mindful of
-/// the stability guarantees you've given your users.
-///
-/// **Example:**
-/// ```rust
-/// impl X {
-///     pub fn as_str(self) -> &str { .. }
-/// }
-/// ```
-declare_clippy_lint! {
-    pub WRONG_PUB_SELF_CONVENTION,
-    restriction,
-    "defining a public method named with an established prefix (like \"into_\") that takes \
-     `self` with the wrong convention"
-}
-
-/// **What it does:** Checks for usage of `ok().expect(..)`.
-///
-/// **Why is this bad?** Because you usually call `expect()` on the `Result`
-/// directly to get a better error message.
-///
-/// **Known problems:** The error type needs to implement `Debug`
-///
-/// **Example:**
-/// ```rust
-/// x.ok().expect("why did I do this again?")
-/// ```
-declare_clippy_lint! {
-    pub OK_EXPECT,
-    style,
-    "using `ok().expect()`, which gives worse error messages than \
-     calling `expect` directly on the Result"
-}
-
-/// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.map_or(_, _)`.
-///
-/// **Known problems:** The order of the arguments is not in execution order
-///
-/// **Example:**
-/// ```rust
-/// x.map(|a| a + 1).unwrap_or(0)
-/// ```
-declare_clippy_lint! {
-    pub OPTION_MAP_UNWRAP_OR,
-    pedantic,
-    "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
-     `map_or(a, f)`"
-}
-
-/// **What it does:** Checks for usage of `_.map(_).unwrap_or_else(_)`.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.map_or_else(_, _)`.
-///
-/// **Known problems:** The order of the arguments is not in execution order.
-///
-/// **Example:**
-/// ```rust
-/// x.map(|a| a + 1).unwrap_or_else(some_function)
-/// ```
-declare_clippy_lint! {
-    pub OPTION_MAP_UNWRAP_OR_ELSE,
-    pedantic,
-    "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
-     `map_or_else(g, f)`"
-}
-
-/// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `result.ok().map_or_else(_, _)`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x.map(|a| a + 1).unwrap_or_else(some_function)
-/// ```
-declare_clippy_lint! {
-    pub RESULT_MAP_UNWRAP_OR_ELSE,
-    pedantic,
-    "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
-     `.ok().map_or_else(g, f)`"
-}
-
-/// **What it does:** Checks for usage of `_.map_or(None, _)`.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.and_then(_)`.
-///
-/// **Known problems:** The order of the arguments is not in execution order.
-///
-/// **Example:**
-/// ```rust
-/// opt.map_or(None, |a| a + 1)
-/// ```
-declare_clippy_lint! {
-    pub OPTION_MAP_OR_NONE,
-    style,
-    "using `Option.map_or(None, f)`, which is more succinctly expressed as \
-     `and_then(f)`"
-}
-
-/// **What it does:** Checks for usage of `_.filter(_).next()`.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.find(_)`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// iter.filter(|x| x == 0).next()
-/// ```
-declare_clippy_lint! {
-    pub FILTER_NEXT,
-    complexity,
-    "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
-}
-
-/// **What it does:** Checks for usage of `_.filter(_).map(_)`,
-/// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as a
-/// single method call.
-///
-/// **Known problems:** Often requires a condition + Option/Iterator creation
-/// inside the closure.
-///
-/// **Example:**
-/// ```rust
-/// iter.filter(|x| x == 0).map(|x| x * 2)
-/// ```
-declare_clippy_lint! {
-    pub FILTER_MAP,
-    pedantic,
-    "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can \
-     usually be written as a single method call"
-}
-
-/// **What it does:** Checks for an iterator search (such as `find()`,
-/// `position()`, or `rposition()`) followed by a call to `is_some()`.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.any(_)`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// iter.find(|x| x == 0).is_some()
-/// ```
-declare_clippy_lint! {
-    pub SEARCH_IS_SOME,
-    complexity,
-    "using an iterator search followed by `is_some()`, which is more succinctly \
-     expressed as a call to `any()`"
-}
-
-/// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
-/// if it starts with a given char.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.starts_with(_)`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// name.chars().next() == Some('_')
-/// ```
-declare_clippy_lint! {
-    pub CHARS_NEXT_CMP,
-    complexity,
-    "using `.chars().next()` to check if a string starts with a char"
-}
-
-/// **What it does:** Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
-/// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
-/// `unwrap_or_default` instead.
-///
-/// **Why is this bad?** The function will always be called and potentially
-/// allocate an object acting as the default.
-///
-/// **Known problems:** If the function has side-effects, not calling it will
-/// change the semantic of the program, but you shouldn't rely on that anyway.
-///
-/// **Example:**
-/// ```rust
-/// foo.unwrap_or(String::new())
-/// ```
-/// this can instead be written:
-/// ```rust
-/// foo.unwrap_or_else(String::new)
-/// ```
-/// or
-/// ```rust
-/// foo.unwrap_or_default()
-/// ```
-declare_clippy_lint! {
-    pub OR_FUN_CALL,
-    perf,
-    "using any `*or` method with a function call, which suggests `*or_else`"
-}
-
-/// **What it does:** Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
-/// etc., and suggests to use `unwrap_or_else` instead
-///
-/// **Why is this bad?** The function will always be called.
-///
-/// **Known problems:** If the function has side-effects, not calling it will
-/// change the semantic of the program, but you shouldn't rely on that anyway.
-///
-/// **Example:**
-/// ```rust
-/// foo.expect(&format("Err {}: {}", err_code, err_msg))
-/// ```
-/// or
-/// ```rust
-/// foo.expect(format("Err {}: {}", err_code, err_msg).as_str())
-/// ```
-/// this can instead be written:
-/// ```rust
-/// foo.unwrap_or_else(|_| panic!("Err {}: {}", err_code, err_msg))
-/// ```
-/// or
-/// ```rust
-/// foo.unwrap_or_else(|_| panic!(format("Err {}: {}", err_code, err_msg).as_str()))
-/// ```
-declare_clippy_lint! {
-    pub EXPECT_FUN_CALL,
-    perf,
-    "using any `expect` method with a function call"
-}
-
-/// **What it does:** Checks for usage of `.clone()` on a `Copy` type.
-///
-/// **Why is this bad?** The only reason `Copy` types implement `Clone` is for
-/// generics, not for using the `clone` method on a concrete type.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// 42u64.clone()
-/// ```
-declare_clippy_lint! {
-    pub CLONE_ON_COPY,
-    complexity,
-    "using `clone` on a `Copy` type"
-}
-
-/// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer,
-/// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
-/// function syntax instead (e.g. `Rc::clone(foo)`).
-///
-/// **Why is this bad?**: Calling '.clone()' on an Rc, Arc, or Weak
-/// can obscure the fact that only the pointer is being cloned, not the underlying
-/// data.
-///
-/// **Example:**
-/// ```rust
-/// x.clone()
-/// ```
-declare_clippy_lint! {
-    pub CLONE_ON_REF_PTR,
-    restriction,
-    "using 'clone' on a ref-counted pointer"
-}
-
-/// **What it does:** Checks for usage of `.clone()` on an `&&T`.
-///
-/// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of
-/// cloning the underlying `T`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn main() {
-///    let x = vec![1];
-///    let y = &&x;
-///    let z = y.clone();
-///    println!("{:p} {:p}",*y, z); // prints out the same pointer
-/// }
-/// ```
-declare_clippy_lint! {
-    pub CLONE_DOUBLE_REF,
-    correctness,
-    "using `clone` on `&&T`"
-}
-
-/// **What it does:** Checks for `new` not returning `Self`.
-///
-/// **Why is this bad?** As a convention, `new` methods are used to make a new
-/// instance of a type.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// impl Foo {
-///     fn new(..) -> NotAFoo {
-///     }
-/// }
-/// ```
-declare_clippy_lint! {
-    pub NEW_RET_NO_SELF,
-    style,
-    "not returning `Self` in a `new` method"
-}
-
-/// **What it does:** Checks for string methods that receive a single-character
-/// `str` as an argument, e.g. `_.split("x")`.
-///
-/// **Why is this bad?** Performing these methods using a `char` is faster than
-/// using a `str`.
-///
-/// **Known problems:** Does not catch multi-byte unicode characters.
-///
-/// **Example:**
-/// `_.split("x")` could be `_.split('x')
-declare_clippy_lint! {
-    pub SINGLE_CHAR_PATTERN,
-    perf,
-    "using a single-character str where a char could be used, e.g. \
-     `_.split(\"x\")`"
-}
-
-/// **What it does:** Checks for getting the inner pointer of a temporary
-/// `CString`.
-///
-/// **Why is this bad?** The inner pointer of a `CString` is only valid as long
-/// as the `CString` is alive.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// let c_str = CString::new("foo").unwrap().as_ptr();
-/// unsafe {
-/// call_some_ffi_func(c_str);
-/// }
-/// ```
-/// Here `c_str` point to a freed address. The correct use would be:
-/// ```rust,ignore
-/// let c_str = CString::new("foo").unwrap();
-/// unsafe {
-///     call_some_ffi_func(c_str.as_ptr());
-/// }
-/// ```
-declare_clippy_lint! {
-    pub TEMPORARY_CSTRING_AS_PTR,
-    correctness,
-    "getting the inner pointer of a temporary `CString`"
-}
-
-/// **What it does:** Checks for use of `.iter().nth()` (and the related
-/// `.iter_mut().nth()`) on standard library types with O(1) element access.
-///
-/// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more
-/// readable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let some_vec = vec![0, 1, 2, 3];
-/// let bad_vec = some_vec.iter().nth(3);
-/// let bad_slice = &some_vec[..].iter().nth(3);
-/// ```
-/// The correct use would be:
-/// ```rust
-/// let some_vec = vec![0, 1, 2, 3];
-/// let bad_vec = some_vec.get(3);
-/// let bad_slice = &some_vec[..].get(3);
-/// ```
-declare_clippy_lint! {
-    pub ITER_NTH,
-    perf,
-    "using `.iter().nth()` on a standard library type with O(1) element access"
-}
-
-/// **What it does:** Checks for use of `.skip(x).next()` on iterators.
-///
-/// **Why is this bad?** `.nth(x)` is cleaner
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let some_vec = vec![0, 1, 2, 3];
-/// let bad_vec = some_vec.iter().skip(3).next();
-/// let bad_slice = &some_vec[..].iter().skip(3).next();
-/// ```
-/// The correct use would be:
-/// ```rust
-/// let some_vec = vec![0, 1, 2, 3];
-/// let bad_vec = some_vec.iter().nth(3);
-/// let bad_slice = &some_vec[..].iter().nth(3);
-/// ```
-declare_clippy_lint! {
-    pub ITER_SKIP_NEXT,
-    style,
-    "using `.skip(x).next()` on an iterator"
-}
-
-/// **What it does:** Checks for use of `.get().unwrap()` (or
-/// `.get_mut().unwrap`) on a standard library type which implements `Index`
-///
-/// **Why is this bad?** Using the Index trait (`[]`) is more clear and more
-/// concise.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let some_vec = vec![0, 1, 2, 3];
-/// let last = some_vec.get(3).unwrap();
-/// *some_vec.get_mut(0).unwrap() = 1;
-/// ```
-/// The correct use would be:
-/// ```rust
-/// let some_vec = vec![0, 1, 2, 3];
-/// let last = some_vec[3];
-/// some_vec[0] = 1;
-/// ```
-declare_clippy_lint! {
-    pub GET_UNWRAP,
-    style,
-    "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
-}
-
-/// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
-/// `&str` or `String`.
-///
-/// **Why is this bad?** `.push_str(s)` is clearer
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let abc = "abc";
-/// let def = String::from("def");
-/// let mut s = String::new();
-/// s.extend(abc.chars());
-/// s.extend(def.chars());
-/// ```
-/// The correct use would be:
-/// ```rust
-/// let abc = "abc";
-/// let def = String::from("def");
-/// let mut s = String::new();
-/// s.push_str(abc);
-/// s.push_str(&def));
-/// ```
-declare_clippy_lint! {
-    pub STRING_EXTEND_CHARS,
-    style,
-    "using `x.extend(s.chars())` where s is a `&str` or `String`"
-}
-
-/// **What it does:** Checks for the use of `.cloned().collect()` on slice to
-/// create a `Vec`.
-///
-/// **Why is this bad?** `.to_vec()` is clearer
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let s = [1,2,3,4,5];
-/// let s2 : Vec<isize> = s[..].iter().cloned().collect();
-/// ```
-/// The better use would be:
-/// ```rust
-/// let s = [1,2,3,4,5];
-/// let s2 : Vec<isize> = s.to_vec();
-/// ```
-declare_clippy_lint! {
-    pub ITER_CLONED_COLLECT,
-    style,
-    "using `.cloned().collect()` on slice to create a `Vec`"
-}
-
-/// **What it does:** Checks for usage of `.chars().last()` or
-/// `.chars().next_back()` on a `str` to check if it ends with a given char.
-///
-/// **Why is this bad?** Readability, this can be written more concisely as
-/// `_.ends_with(_)`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// name.chars().last() == Some('_') || name.chars().next_back() == Some('-')
-/// ```
-declare_clippy_lint! {
-    pub CHARS_LAST_CMP,
-    style,
-    "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
-}
-
-/// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the
-/// types before and after the call are the same.
-///
-/// **Why is this bad?** The call is unnecessary.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x: &[i32] = &[1,2,3,4,5];
-/// do_stuff(x.as_ref());
-/// ```
-/// The correct use would be:
-/// ```rust
-/// let x: &[i32] = &[1,2,3,4,5];
-/// do_stuff(x);
-/// ```
-declare_clippy_lint! {
-    pub USELESS_ASREF,
-    complexity,
-    "using `as_ref` where the types before and after the call are the same"
-}
-
-
-/// **What it does:** Checks for using `fold` when a more succinct alternative exists.
-/// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
-/// `sum` or `product`.
-///
-/// **Why is this bad?** Readability.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
-/// ```
-/// This could be written as:
-/// ```rust
-/// let _ = (0..3).any(|x| x > 2);
-/// ```
-declare_clippy_lint! {
-    pub UNNECESSARY_FOLD,
-    style,
-    "using `fold` when a more succinct alternative exists"
-}
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            OPTION_UNWRAP_USED,
-            RESULT_UNWRAP_USED,
-            SHOULD_IMPLEMENT_TRAIT,
-            WRONG_SELF_CONVENTION,
-            WRONG_PUB_SELF_CONVENTION,
-            OK_EXPECT,
-            OPTION_MAP_UNWRAP_OR,
-            OPTION_MAP_UNWRAP_OR_ELSE,
-            RESULT_MAP_UNWRAP_OR_ELSE,
-            OPTION_MAP_OR_NONE,
-            OR_FUN_CALL,
-            EXPECT_FUN_CALL,
-            CHARS_NEXT_CMP,
-            CHARS_LAST_CMP,
-            CLONE_ON_COPY,
-            CLONE_ON_REF_PTR,
-            CLONE_DOUBLE_REF,
-            NEW_RET_NO_SELF,
-            SINGLE_CHAR_PATTERN,
-            SEARCH_IS_SOME,
-            TEMPORARY_CSTRING_AS_PTR,
-            FILTER_NEXT,
-            FILTER_MAP,
-            ITER_NTH,
-            ITER_SKIP_NEXT,
-            GET_UNWRAP,
-            STRING_EXTEND_CHARS,
-            ITER_CLONED_COLLECT,
-            USELESS_ASREF,
-            UNNECESSARY_FOLD
-        )
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    #[allow(cyclomatic_complexity)]
-    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        if in_macro(expr.span) {
-            return;
-        }
-
-        match expr.node {
-            hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => {
-                // Chain calls
-                // GET_UNWRAP needs to be checked before general `UNWRAP` lints
-                if let Some(arglists) = method_chain_args(expr, &["get", "unwrap"]) {
-                    lint_get_unwrap(cx, expr, arglists[0], false);
-                } else if let Some(arglists) = method_chain_args(expr, &["get_mut", "unwrap"]) {
-                    lint_get_unwrap(cx, expr, arglists[0], true);
-                } else if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                    lint_unwrap(cx, expr, arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["ok", "expect"]) {
-                    lint_ok_expect(cx, expr, arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or"]) {
-                    lint_map_unwrap_or(cx, expr, arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["map", "unwrap_or_else"]) {
-                    lint_map_unwrap_or_else(cx, expr, arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["map_or"]) {
-                    lint_map_or_none(cx, expr, arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["filter", "next"]) {
-                    lint_filter_next(cx, expr, arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["filter", "map"]) {
-                    lint_filter_map(cx, expr, arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["filter_map", "map"]) {
-                    lint_filter_map_map(cx, expr, arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["filter", "flat_map"]) {
-                    lint_filter_flat_map(cx, expr, arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["filter_map", "flat_map"]) {
-                    lint_filter_map_flat_map(cx, expr, arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["find", "is_some"]) {
-                    lint_search_is_some(cx, expr, "find", arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["position", "is_some"]) {
-                    lint_search_is_some(cx, expr, "position", arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["rposition", "is_some"]) {
-                    lint_search_is_some(cx, expr, "rposition", arglists[0], arglists[1]);
-                } else if let Some(arglists) = method_chain_args(expr, &["extend"]) {
-                    lint_extend(cx, expr, arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["unwrap", "as_ptr"]) {
-                    lint_cstring_as_ptr(cx, expr, &arglists[0][0], &arglists[1][0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["iter", "nth"]) {
-                    lint_iter_nth(cx, expr, arglists[0], false);
-                } else if let Some(arglists) = method_chain_args(expr, &["iter_mut", "nth"]) {
-                    lint_iter_nth(cx, expr, arglists[0], true);
-                } else if method_chain_args(expr, &["skip", "next"]).is_some() {
-                    lint_iter_skip_next(cx, expr);
-                } else if let Some(arglists) = method_chain_args(expr, &["cloned", "collect"]) {
-                    lint_iter_cloned_collect(cx, expr, arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["as_ref"]) {
-                    lint_asref(cx, expr, "as_ref", arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["as_mut"]) {
-                    lint_asref(cx, expr, "as_mut", arglists[0]);
-                } else if let Some(arglists) = method_chain_args(expr, &["fold"]) {
-                    lint_unnecessary_fold(cx, expr, arglists[0]);
-                }
-
-                lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
-                lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
-
-                let self_ty = cx.tables.expr_ty_adjusted(&args[0]);
-                if args.len() == 1 && method_call.ident.name == "clone" {
-                    lint_clone_on_copy(cx, expr, &args[0], self_ty);
-                    lint_clone_on_ref_ptr(cx, expr, &args[0]);
-                }
-
-                match self_ty.sty {
-                    ty::TyRef(_, ty, _) if ty.sty == ty::TyStr => for &(method, pos) in &PATTERN_METHODS {
-                        if method_call.ident.name == method && args.len() > pos {
-                            lint_single_char_pattern(cx, expr, &args[pos]);
-                        }
-                    },
-                    _ => (),
-                }
-            },
-            hir::ExprKind::Binary(op, ref lhs, ref rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
-                let mut info = BinaryExprInfo {
-                    expr,
-                    chain: lhs,
-                    other: rhs,
-                    eq: op.node == hir::BinOpKind::Eq,
-                };
-                lint_binary_expr_with_method_call(cx, &mut info);
-            },
-            _ => (),
-        }
-    }
-
-    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, implitem: &'tcx hir::ImplItem) {
-        if in_external_macro(cx.sess(), implitem.span) {
-            return;
-        }
-        let name = implitem.ident.name;
-        let parent = cx.tcx.hir.get_parent(implitem.id);
-        let item = cx.tcx.hir.expect_item(parent);
-        if_chain! {
-            if let hir::ImplItemKind::Method(ref sig, id) = implitem.node;
-            if let Some(first_arg_ty) = sig.decl.inputs.get(0);
-            if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir.body(id)).next();
-            if let hir::ItemKind::Impl(_, _, _, _, None, ref self_ty, _) = item.node;
-            then {
-                if cx.access_levels.is_exported(implitem.id) {
-                // check missing trait implementations
-                    for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
-                        if name == method_name &&
-                        sig.decl.inputs.len() == n_args &&
-                        out_type.matches(cx, &sig.decl.output) &&
-                        self_kind.matches(cx, first_arg_ty, first_arg, self_ty, false, &implitem.generics) {
-                            span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
-                                "defining a method called `{}` on this type; consider implementing \
-                                the `{}` trait or choosing a less ambiguous name", name, trait_name));
-                        }
-                    }
-                }
-
-                // check conventions w.r.t. conversion method names and predicates
-                let def_id = cx.tcx.hir.local_def_id(item.id);
-                let ty = cx.tcx.type_of(def_id);
-                let is_copy = is_copy(cx, ty);
-                for &(ref conv, self_kinds) in &CONVENTIONS {
-                    if_chain! {
-                        if conv.check(&name.as_str());
-                        if !self_kinds
-                            .iter()
-                            .any(|k| k.matches(cx, first_arg_ty, first_arg, self_ty, is_copy, &implitem.generics));
-                        then {
-                            let lint = if item.vis.node.is_pub() {
-                                WRONG_PUB_SELF_CONVENTION
-                            } else {
-                                WRONG_SELF_CONVENTION
-                            };
-                            span_lint(cx,
-                                      lint,
-                                      first_arg.pat.span,
-                                      &format!("methods called `{}` usually take {}; consider choosing a less \
-                                                ambiguous name",
-                                               conv,
-                                               &self_kinds.iter()
-                                                          .map(|k| k.description())
-                                                          .collect::<Vec<_>>()
-                                                          .join(" or ")));
-                        }
-                    }
-                }
-
-                let ret_ty = return_ty(cx, implitem.id);
-                if name == "new" &&
-                   !ret_ty.walk().any(|t| same_tys(cx, t, ty)) {
-                    span_lint(cx,
-                              NEW_RET_NO_SELF,
-                              implitem.span,
-                              "methods called `new` usually return `Self`");
-                }
-            }
-        }
-    }
-}
-
-/// Checks for the `OR_FUN_CALL` lint.
-fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
-    /// Check for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
-    fn check_unwrap_or_default(
-        cx: &LateContext<'_, '_>,
-        name: &str,
-        fun: &hir::Expr,
-        self_expr: &hir::Expr,
-        arg: &hir::Expr,
-        or_has_args: bool,
-        span: Span,
-    ) -> bool {
-        if or_has_args {
-            return false;
-        }
-
-        if name == "unwrap_or" {
-            if let hir::ExprKind::Path(ref qpath) = fun.node {
-                let path = &*last_path_segment(qpath).ident.as_str();
-
-                if ["default", "new"].contains(&path) {
-                    let arg_ty = cx.tables.expr_ty(arg);
-                    let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT) {
-                        default_trait_id
-                    } else {
-                        return false;
-                    };
-
-                    if implements_trait(cx, arg_ty, default_trait_id, &[]) {
-                        span_lint_and_sugg(
-                            cx,
-                            OR_FUN_CALL,
-                            span,
-                            &format!("use of `{}` followed by a call to `{}`", name, path),
-                            "try this",
-                            format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_")),
-                        );
-                        return true;
-                    }
-                }
-            }
-        }
-
-        false
-    }
-
-    /// Check for `*or(foo())`.
-    #[allow(too_many_arguments)]
-    fn check_general_case(
-        cx: &LateContext<'_, '_>,
-        name: &str,
-        method_span: Span,
-        fun_span: Span,
-        self_expr: &hir::Expr,
-        arg: &hir::Expr,
-        or_has_args: bool,
-        span: Span,
-    ) {
-        // (path, fn_has_argument, methods, suffix)
-        let know_types: &[(&[_], _, &[_], _)] = &[
-            (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
-            (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
-            (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
-            (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
-        ];
-
-        // early check if the name is one we care about
-        if know_types.iter().all(|k| !k.2.contains(&name)) {
-            return;
-        }
-
-        // don't lint for constant values
-        let owner_def = cx.tcx.hir.get_parent_did(arg.id);
-        let promotable = cx.tcx.rvalue_promotable_map(owner_def).contains(&arg.hir_id.local_id);
-        if promotable {
-            return;
-        }
-
-        let self_ty = cx.tables.expr_ty(self_expr);
-
-        let (fn_has_arguments, poss, suffix) = if let Some(&(_, fn_has_arguments, poss, suffix)) =
-            know_types.iter().find(|&&i| match_type(cx, self_ty, i.0))
-        {
-            (fn_has_arguments, poss, suffix)
-        } else {
-            return;
-        };
-
-        if !poss.contains(&name) {
-            return;
-        }
-
-        let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
-            (true, _) => format!("|_| {}", snippet(cx, arg.span, "..")).into(),
-            (false, false) => format!("|| {}", snippet(cx, arg.span, "..")).into(),
-            (false, true) => snippet(cx, fun_span, ".."),
-        };
-        let span_replace_word = method_span.with_hi(span.hi());
-        span_lint_and_sugg(
-            cx,
-            OR_FUN_CALL,
-            span_replace_word,
-            &format!("use of `{}` followed by a function call", name),
-            "try this",
-            format!("{}_{}({})", name, suffix, sugg),
-        );
-    }
-
-    if args.len() == 2 {
-        match args[1].node {
-            hir::ExprKind::Call(ref fun, ref or_args) => {
-                let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
-                    check_general_case(cx, name, method_span, fun.span, &args[0], &args[1], or_has_args, expr.span);
-                }
-            },
-            hir::ExprKind::MethodCall(_, span, ref or_args) => {
-                check_general_case(cx, name, method_span, span, &args[0], &args[1], !or_args.is_empty(), expr.span)
-            },
-            _ => {},
-        }
-    }
-}
-
-/// Checks for the `EXPECT_FUN_CALL` lint.
-fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
-    fn extract_format_args(arg: &hir::Expr) -> Option<&hir::HirVec<hir::Expr>> {
-        if let hir::ExprKind::AddrOf(_, ref addr_of) = arg.node {
-            if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = addr_of.node {
-                if is_expn_of(inner_fun.span, "format").is_some() && inner_args.len() == 1 {
-                    if let hir::ExprKind::Call(_, ref format_args) = inner_args[0].node {
-                        return Some(format_args);
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    fn generate_format_arg_snippet(cx: &LateContext<'_, '_>, a: &hir::Expr) -> String {
-        if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node {
-            if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node {
-                if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node {
-                    return snippet(cx, format_arg_expr_tup[0].span, "..").into_owned();
-                }
-            }
-        };
-
-        snippet(cx, a.span, "..").into_owned()
-    }
-
-    fn check_general_case(
-        cx: &LateContext<'_, '_>,
-        name: &str,
-        method_span: Span,
-        self_expr: &hir::Expr,
-        arg: &hir::Expr,
-        span: Span,
-    ) {
-        if name != "expect" {
-            return;
-        }
-
-        let self_type = cx.tables.expr_ty(self_expr);
-        let known_types = &[&paths::OPTION, &paths::RESULT];
-
-        // if not a known type, return early
-        if known_types.iter().all(|&k| !match_type(cx, self_type, k)) {
-            return;
-        }
-
-        // don't lint for constant values
-        let owner_def = cx.tcx.hir.get_parent_did(arg.id);
-        let promotable = cx.tcx.rvalue_promotable_map(owner_def).contains(&arg.hir_id.local_id);
-        if promotable {
-            return;
-        }
-
-        let closure = if match_type(cx, self_type, &paths::OPTION) { "||" } else { "|_|" };
-        let span_replace_word = method_span.with_hi(span.hi());
-
-        if let Some(format_args) = extract_format_args(arg) {
-            let args_len = format_args.len();
-            let args: Vec<String> = format_args
-                .into_iter()
-                .take(args_len - 1)
-                .map(|a| generate_format_arg_snippet(cx, a))
-                .collect();
-
-            let sugg = args.join(", ");
-
-            span_lint_and_sugg(
-                cx,
-                EXPECT_FUN_CALL,
-                span_replace_word,
-                &format!("use of `{}` followed by a function call", name),
-                "try this",
-                format!("unwrap_or_else({} panic!({}))", closure, sugg),
-            );
-
-            return;
-        }
-
-        let sugg: Cow<'_, _> = snippet(cx, arg.span, "..");
-
-        span_lint_and_sugg(
-            cx,
-            EXPECT_FUN_CALL,
-            span_replace_word,
-            &format!("use of `{}` followed by a function call", name),
-            "try this",
-            format!("unwrap_or_else({} panic!({}))", closure, sugg),
-        );
-    }
-
-    if args.len() == 2 {
-        match args[1].node {
-            hir::ExprKind::Lit(_) => {},
-            _ => check_general_case(cx, name, method_span, &args[0], &args[1], expr.span),
-        }
-    }
-}
-
-/// Checks for the `CLONE_ON_COPY` lint.
-fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty<'_>) {
-    let ty = cx.tables.expr_ty(expr);
-    if let ty::TyRef(_, inner, _) = arg_ty.sty {
-        if let ty::TyRef(_, innermost, _) = inner.sty {
-            span_lint_and_then(
-                cx,
-                CLONE_DOUBLE_REF,
-                expr.span,
-                "using `clone` on a double-reference; \
-                 this will copy the reference instead of cloning the inner type",
-                |db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
-                    let mut ty = innermost;
-                    let mut n = 0;
-                    while let ty::TyRef(_, inner, _) = ty.sty {
-                        ty = inner;
-                        n += 1;
-                    }
-                    let refs: String = iter::repeat('&').take(n + 1).collect();
-                    let derefs: String = iter::repeat('*').take(n).collect();
-                    let explicit = format!("{}{}::clone({})", refs, ty, snip);
-                    db.span_suggestion(expr.span, "try dereferencing it", format!("{}({}{}).clone()", refs, derefs, snip.deref()));
-                    db.span_suggestion(expr.span, "or try being explicit about what type to clone", explicit);
-                },
-            );
-            return; // don't report clone_on_copy
-        }
-    }
-
-    if is_copy(cx, ty) {
-        let snip;
-        if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
-            if let ty::TyRef(..) = cx.tables.expr_ty(arg).sty {
-                let parent = cx.tcx.hir.get_parent_node(expr.id);
-                match cx.tcx.hir.get(parent) {
-                    hir::map::NodeExpr(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::map::NodeStmt(stmt) => {
-                        if let hir::StmtKind::Decl(ref decl, _) = stmt.node {
-                            if let hir::DeclKind::Local(ref loc) = decl.node {
-                                if let hir::PatKind::Ref(..) = loc.pat.node {
-                                    // let ref y = *x borrows x, let ref y = x.clone() does not
-                                    return;
-                                }
-                            }
-                        }
-                    },
-                    _ => {},
-                }
-                snip = Some(("try dereferencing it", format!("{}", snippet.deref())));
-            } else {
-                snip = Some(("try removing the `clone` call", format!("{}", snippet)));
-            }
-        } else {
-            snip = None;
-        }
-        span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| {
-            if let Some((text, snip)) = snip {
-                db.span_suggestion(expr.span, text, snip);
-            }
-        });
-    }
-}
-
-fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
-
-    if let ty::TyAdt(_, subst) = obj_ty.sty {
-        let caller_type = if match_type(cx, obj_ty, &paths::RC) {
-            "Rc"
-        } else if match_type(cx, obj_ty, &paths::ARC) {
-            "Arc"
-        } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
-            "Weak"
-        } else {
-            return;
-        };
-
-        span_lint_and_sugg(
-            cx,
-            CLONE_ON_REF_PTR,
-            expr.span,
-            "using '.clone()' on a ref-counted pointer",
-            "try this",
-            format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet(cx, arg.span, "_")),
-        );
-    }
-}
-
-
-fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
-    let arg = &args[1];
-    if let Some(arglists) = method_chain_args(arg, &["chars"]) {
-        let target = &arglists[0][0];
-        let self_ty = walk_ptrs_ty(cx.tables.expr_ty(target));
-        let ref_str = if self_ty.sty == ty::TyStr {
-            ""
-        } else if match_type(cx, self_ty, &paths::STRING) {
-            "&"
-        } else {
-            return;
-        };
-
-        span_lint_and_sugg(
-            cx,
-            STRING_EXTEND_CHARS,
-            expr.span,
-            "calling `.extend(_.chars())`",
-            "try this",
-            format!(
-                "{}.push_str({}{})",
-                snippet(cx, args[0].span, "_"),
-                ref_str,
-                snippet(cx, target.span, "_")
-            ),
-        );
-    }
-}
-
-fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
-    if match_type(cx, obj_ty, &paths::STRING) {
-        lint_string_extend(cx, expr, args);
-    }
-}
-
-fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) {
-    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 Def::Method(did) = cx.tables.qpath_def(path, fun.hir_id);
-        if match_def_path(cx.tcx, did, &paths::CSTRING_NEW);
-        then {
-            span_lint_and_then(
-                cx,
-                TEMPORARY_CSTRING_AS_PTR,
-                expr.span,
-                "you are getting the inner pointer of a temporary `CString`",
-                |db| {
-                    db.note("that pointer will be invalid outside this expression");
-                    db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
-                });
-        }
-    }
-}
-
-fn lint_iter_cloned_collect(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr]) {
-    if match_type(cx, cx.tables.expr_ty(expr), &paths::VEC)
-        && derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some()
-    {
-        span_lint(
-            cx,
-            ITER_CLONED_COLLECT,
-            expr.span,
-            "called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
-             more readable",
-        );
-    }
-}
-
-fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: &[hir::Expr]) {
-    // Check that this is a call to Iterator::fold rather than just some function called fold
-    if !match_trait_method(cx, expr, &paths::ITERATOR) {
-        return;
-    }
-
-    assert!(fold_args.len() == 3,
-        "Expected fold_args to have three entries - the receiver, the initial value and the closure");
-
-    fn check_fold_with_op(
-        cx: &LateContext<'_, '_>,
-        fold_args: &[hir::Expr],
-        op: hir::BinOpKind,
-        replacement_method_name: &str,
-        replacement_has_args: bool) {
-
-        if_chain! {
-            // Extract the body of the closure passed to fold
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].node;
-            let closure_body = cx.tcx.hir.body(body_id);
-            let closure_expr = remove_blocks(&closure_body.value);
-
-            // Check if the closure body is of the form `acc <op> some_expr(x)`
-            if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.node;
-            if bin_op.node == op;
-
-            // Extract the names of the two arguments to the closure
-            if let Some(first_arg_ident) = get_arg_name(&closure_body.arguments[0].pat);
-            if let Some(second_arg_ident) = get_arg_name(&closure_body.arguments[1].pat);
-
-            if match_var(&*left_expr, first_arg_ident);
-            if replacement_has_args || match_var(&*right_expr, second_arg_ident);
-
-            then {
-                // Span containing `.fold(...)`
-                let next_point = cx.sess().codemap().next_point(fold_args[0].span);
-                let fold_span = next_point.with_hi(fold_args[2].span.hi() + BytePos(1));
-
-                let sugg = if replacement_has_args {
-                    format!(
-                        ".{replacement}(|{s}| {r})",
-                        replacement = replacement_method_name,
-                        s = second_arg_ident,
-                        r = snippet(cx, right_expr.span, "EXPR"),
-                    )
-                } else {
-                    format!(
-                        ".{replacement}()",
-                        replacement = replacement_method_name,
-                    )
-                };
-
-                span_lint_and_sugg(
-                    cx,
-                    UNNECESSARY_FOLD,
-                    fold_span,
-                    // TODO #2371 don't suggest e.g. .any(|x| f(x)) if we can suggest .any(f)
-                    "this `.fold` can be written more succinctly using another method",
-                    "try",
-                    sugg,
-                );
-            }
-        }
-    }
-
-    // Check if the first argument to .fold is a suitable literal
-    match fold_args[1].node {
-        hir::ExprKind::Lit(ref lit) => {
-            match lit.node {
-                ast::LitKind::Bool(false) => check_fold_with_op(
-                    cx, fold_args, hir::BinOpKind::Or, "any", true
-                ),
-                ast::LitKind::Bool(true) => check_fold_with_op(
-                    cx, fold_args, hir::BinOpKind::And, "all", true
-                ),
-                ast::LitKind::Int(0, _) => check_fold_with_op(
-                    cx, fold_args, hir::BinOpKind::Add, "sum", false
-                ),
-                ast::LitKind::Int(1, _) => check_fold_with_op(
-                    cx, fold_args, hir::BinOpKind::Mul, "product", false
-                ),
-                _ => return
-            }
-        }
-        _ => return
-    };
-}
-
-fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::Expr], is_mut: bool) {
-    let mut_str = if is_mut { "_mut" } else { "" };
-    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
-        "slice"
-    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC) {
-        "Vec"
-    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC_DEQUE) {
-        "VecDeque"
-    } else {
-        return; // caller is not a type that we want to lint
-    };
-
-    span_lint(
-        cx,
-        ITER_NTH,
-        expr.span,
-        &format!(
-            "called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
-            mut_str,
-            caller_type
-        ),
-    );
-}
-
-fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) {
-    // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap,
-    // because they do not implement `IndexMut`
-    let expr_ty = cx.tables.expr_ty(&get_args[0]);
-    let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
-        "slice"
-    } else if match_type(cx, expr_ty, &paths::VEC) {
-        "Vec"
-    } else if match_type(cx, expr_ty, &paths::VEC_DEQUE) {
-        "VecDeque"
-    } else if !is_mut && match_type(cx, expr_ty, &paths::HASHMAP) {
-        "HashMap"
-    } else if !is_mut && match_type(cx, expr_ty, &paths::BTREEMAP) {
-        "BTreeMap"
-    } else {
-        return; // caller is not a type that we want to lint
-    };
-
-    let mut_str = if is_mut { "_mut" } else { "" };
-    let borrow_str = if is_mut { "&mut " } else { "&" };
-    span_lint_and_sugg(
-        cx,
-        GET_UNWRAP,
-        expr.span,
-        &format!(
-            "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
-            mut_str,
-            caller_type
-        ),
-        "try this",
-        format!(
-            "{}{}[{}]",
-            borrow_str,
-            snippet(cx, get_args[0].span, "_"),
-            snippet(cx, get_args[1].span, "_")
-        ),
-    );
-}
-
-fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
-    // lint if caller of skip is an Iterator
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        span_lint(
-            cx,
-            ITER_SKIP_NEXT,
-            expr.span,
-            "called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`",
-        );
-    }
-}
-
-fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Option<sugg::Sugg<'static>> {
-    fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
-        match ty.sty {
-            ty::TySlice(_) => true,
-            ty::TyAdt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
-            ty::TyAdt(..) => match_type(cx, ty, &paths::VEC),
-            ty::TyArray(_, size) => size.assert_usize(cx.tcx).expect("array length") < 32,
-            ty::TyRef(_, inner, _) => may_slice(cx, inner),
-            _ => false,
-        }
-    }
-
-    if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node {
-        if path.ident.name == "iter" && may_slice(cx, cx.tables.expr_ty(&args[0])) {
-            sugg::Sugg::hir_opt(cx, &args[0]).map(|sugg| sugg.addr())
-        } else {
-            None
-        }
-    } else {
-        match ty.sty {
-            ty::TySlice(_) => sugg::Sugg::hir_opt(cx, expr),
-            ty::TyAdt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
-            ty::TyRef(_, inner, _) => if may_slice(cx, inner) {
-                sugg::Sugg::hir_opt(cx, expr)
-            } else {
-                None
-            },
-            _ => None,
-        }
-    }
-}
-
-/// lint use of `unwrap()` for `Option`s and `Result`s
-fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::Expr]) {
-    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
-
-    let mess = if match_type(cx, obj_ty, &paths::OPTION) {
-        Some((OPTION_UNWRAP_USED, "an Option", "None"))
-    } else if match_type(cx, obj_ty, &paths::RESULT) {
-        Some((RESULT_UNWRAP_USED, "a Result", "Err"))
-    } else {
-        None
-    };
-
-    if let Some((lint, kind, none_value)) = mess {
-        span_lint(
-            cx,
-            lint,
-            expr.span,
-            &format!(
-                "used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \
-                 using expect() to provide a better panic \
-                 message",
-                kind,
-                none_value
-            ),
-        );
-    }
-}
-
-/// lint use of `ok().expect()` for `Result`s
-fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr, ok_args: &[hir::Expr]) {
-    // lint if the caller of `ok()` is a `Result`
-    if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &paths::RESULT) {
-        let result_type = cx.tables.expr_ty(&ok_args[0]);
-        if let Some(error_type) = get_error_type(cx, result_type) {
-            if has_debug_impl(error_type, cx) {
-                span_lint(
-                    cx,
-                    OK_EXPECT,
-                    expr.span,
-                    "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`",
-                );
-            }
-        }
-    }
-}
-
-/// lint use of `map().unwrap_or()` for `Option`s
-fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hir::Expr], unwrap_args: &[hir::Expr]) {
-    // lint if the caller of `map()` is an `Option`
-    if match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION) {
-        // get snippets for args to map() and unwrap_or()
-        let map_snippet = snippet(cx, map_args[1].span, "..");
-        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
-        // lint message
-        // comparing the snippet from source to raw text ("None") below is safe
-        // because we already have checked the type.
-        let arg = if unwrap_snippet == "None" {
-            "None"
-        } else {
-            "a"
-        };
-        let suggest = if unwrap_snippet == "None" {
-            "and_then(f)"
-        } else {
-            "map_or(a, f)"
-        };
-        let msg = &format!(
-            "called `map(f).unwrap_or({})` on an Option value. \
-             This can be done more directly by calling `{}` instead",
-            arg,
-            suggest
-        );
-        // lint, with note if neither arg is > 1 line and both map() and
-        // unwrap_or() have the same span
-        let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
-        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
-        if same_span && !multiline {
-            let suggest = if unwrap_snippet == "None" {
-                format!("and_then({})", map_snippet)
-            } else {
-                format!("map_or({}, {})", unwrap_snippet, map_snippet)
-            };
-            let note = format!(
-                "replace `map({}).unwrap_or({})` with `{}`",
-                map_snippet,
-                unwrap_snippet,
-                suggest
-            );
-            span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, &note);
-        } else if same_span && multiline {
-            span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg);
-        };
-    }
-}
-
-/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
-fn lint_map_unwrap_or_else<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx hir::Expr,
-    map_args: &'tcx [hir::Expr],
-    unwrap_args: &'tcx [hir::Expr],
-) {
-    // lint if the caller of `map()` is an `Option`
-    let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
-    let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
-    if is_option || is_result {
-        // lint message
-        let msg = if is_option {
-            "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \
-             `map_or_else(g, f)` instead"
-        } else {
-            "called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \
-             `ok().map_or_else(g, f)` instead"
-        };
-        // get snippets for args to map() and unwrap_or_else()
-        let map_snippet = snippet(cx, map_args[1].span, "..");
-        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
-        // lint, with note if neither arg is > 1 line and both map() and
-        // unwrap_or_else() have the same span
-        let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
-        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
-        if same_span && !multiline {
-            span_note_and_lint(
-                cx,
-                if is_option {
-                    OPTION_MAP_UNWRAP_OR_ELSE
-                } else {
-                    RESULT_MAP_UNWRAP_OR_ELSE
-                },
-                expr.span,
-                msg,
-                expr.span,
-                &format!(
-                    "replace `map({0}).unwrap_or_else({1})` with `{2}map_or_else({1}, {0})`",
-                    map_snippet,
-                    unwrap_snippet,
-                    if is_result { "ok()." } else { "" }
-                ),
-            );
-        } else if same_span && multiline {
-            span_lint(
-                cx,
-                if is_option {
-                    OPTION_MAP_UNWRAP_OR_ELSE
-                } else {
-                    RESULT_MAP_UNWRAP_OR_ELSE
-                },
-                expr.span,
-                msg,
-            );
-        };
-    }
-}
-
-/// lint use of `_.map_or(None, _)` for `Option`s
-fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) {
-    if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) {
-        // check if the first non-self argument to map_or() is None
-        let map_or_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].node {
-            match_qpath(qpath, &paths::OPTION_NONE)
-        } else {
-            false
-        };
-
-        if map_or_arg_is_none {
-            // lint message
-            let msg = "called `map_or(None, f)` on an Option value. This can be done more directly by calling \
-                       `and_then(f)` instead";
-            let map_or_self_snippet = snippet(cx, map_or_args[0].span, "..");
-            let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
-            let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
-            span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
-                db.span_suggestion(expr.span, "try using and_then instead", hint);
-            });
-        }
-    }
-}
-
-/// 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
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
-                   `.find(p)` instead.";
-        let filter_snippet = snippet(cx, filter_args[1].span, "..");
-        if filter_snippet.lines().count() <= 1 {
-            // add note if not multi-line
-            span_note_and_lint(
-                cx,
-                FILTER_NEXT,
-                expr.span,
-                msg,
-                expr.span,
-                &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
-            );
-        } else {
-            span_lint(cx, FILTER_NEXT, expr.span, msg);
-        }
-    }
-}
-
-/// lint use of `filter().map()` for `Iterators`
-fn lint_filter_map<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx hir::Expr,
-    _filter_args: &'tcx [hir::Expr],
-    _map_args: &'tcx [hir::Expr],
-) {
-    // lint if caller of `.filter().map()` is an Iterator
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `filter(p).map(q)` on an `Iterator`. \
-                   This is more succinctly expressed by calling `.filter_map(..)` instead.";
-        span_lint(cx, FILTER_MAP, expr.span, msg);
-    }
-}
-
-/// lint use of `filter().map()` for `Iterators`
-fn lint_filter_map_map<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx hir::Expr,
-    _filter_args: &'tcx [hir::Expr],
-    _map_args: &'tcx [hir::Expr],
-) {
-    // lint if caller of `.filter().map()` is an Iterator
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
-                   This is more succinctly expressed by only calling `.filter_map(..)` instead.";
-        span_lint(cx, FILTER_MAP, expr.span, msg);
-    }
-}
-
-/// lint use of `filter().flat_map()` for `Iterators`
-fn lint_filter_flat_map<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx hir::Expr,
-    _filter_args: &'tcx [hir::Expr],
-    _map_args: &'tcx [hir::Expr],
-) {
-    // lint if caller of `.filter().flat_map()` is an Iterator
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \
-                   This is more succinctly expressed by calling `.flat_map(..)` \
-                   and filtering by returning an empty Iterator.";
-        span_lint(cx, FILTER_MAP, expr.span, msg);
-    }
-}
-
-/// lint use of `filter_map().flat_map()` for `Iterators`
-fn lint_filter_map_flat_map<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx hir::Expr,
-    _filter_args: &'tcx [hir::Expr],
-    _map_args: &'tcx [hir::Expr],
-) {
-    // lint if caller of `.filter_map().flat_map()` is an Iterator
-    if match_trait_method(cx, expr, &paths::ITERATOR) {
-        let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \
-                   This is more succinctly expressed by calling `.flat_map(..)` \
-                   and filtering by returning an empty Iterator.";
-        span_lint(cx, FILTER_MAP, expr.span, msg);
-    }
-}
-
-/// lint searching an Iterator followed by `is_some()`
-fn lint_search_is_some<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx hir::Expr,
-    search_method: &str,
-    search_args: &'tcx [hir::Expr],
-    is_some_args: &'tcx [hir::Expr],
-) {
-    // lint if caller of search is an Iterator
-    if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) {
-        let msg = format!(
-            "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
-             expressed by calling `any()`.",
-            search_method
-        );
-        let search_snippet = snippet(cx, search_args[1].span, "..");
-        if search_snippet.lines().count() <= 1 {
-            // add note if not multi-line
-            span_note_and_lint(
-                cx,
-                SEARCH_IS_SOME,
-                expr.span,
-                &msg,
-                expr.span,
-                &format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet),
-            );
-        } else {
-            span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
-        }
-    }
-}
-
-/// Used for `lint_binary_expr_with_method_call`.
-#[derive(Copy, Clone)]
-struct BinaryExprInfo<'a> {
-    expr: &'a hir::Expr,
-    chain: &'a hir::Expr,
-    other: &'a hir::Expr,
-    eq: bool,
-}
-
-/// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
-fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut BinaryExprInfo<'_>) {
-    macro_rules! lint_with_both_lhs_and_rhs {
-        ($func:ident, $cx:expr, $info:ident) => {
-            if !$func($cx, $info) {
-                ::std::mem::swap(&mut $info.chain, &mut $info.other);
-                if $func($cx, $info) {
-                    return;
-                }
-            }
-        }
-    }
-
-    lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
-    lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
-    lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
-    lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
-}
-
-/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints.
-fn lint_chars_cmp(
-    cx: &LateContext<'_, '_>,
-    info: &BinaryExprInfo<'_>,
-    chain_methods: &[&str],
-    lint: &'static Lint,
-    suggest: &str,
-) -> bool {
-    if_chain! {
-        if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.node;
-        if arg_char.len() == 1;
-        if let hir::ExprKind::Path(ref qpath) = fun.node;
-        if let Some(segment) = single_segment_path(qpath);
-        if segment.ident.name == "Some";
-        then {
-            let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
-
-            if self_ty.sty != ty::TyStr {
-                return false;
-            }
-
-            span_lint_and_sugg(cx,
-                               lint,
-                               info.expr.span,
-                               &format!("you should use the `{}` method", suggest),
-                               "like this",
-                               format!("{}{}.{}({})",
-                                       if info.eq { "" } else { "!" },
-                                       snippet(cx, args[0][0].span, "_"),
-                                       suggest,
-                                       snippet(cx, arg_char[0].span, "_")));
-
-            return true;
-        }
-    }
-
-    false
-}
-
-/// Checks for the `CHARS_NEXT_CMP` lint.
-fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
-    lint_chars_cmp(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
-}
-
-/// Checks for the `CHARS_LAST_CMP` lint.
-fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
-    if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_NEXT_CMP, "ends_with") {
-        true
-    } else {
-        lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_NEXT_CMP, "ends_with")
-    }
-}
-
-/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
-fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    info: &BinaryExprInfo<'_>,
-    chain_methods: &[&str],
-    lint: &'static Lint,
-    suggest: &str,
-) -> bool {
-    if_chain! {
-        if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Lit(ref lit) = info.other.node;
-        if let ast::LitKind::Char(c) = lit.node;
-        then {
-            span_lint_and_sugg(
-                cx,
-                lint,
-                info.expr.span,
-                &format!("you should use the `{}` method", suggest),
-                "like this",
-                format!("{}{}.{}('{}')",
-                        if info.eq { "" } else { "!" },
-                        snippet(cx, args[0][0].span, "_"),
-                        suggest,
-                        c)
-            );
-
-            return true;
-        }
-    }
-
-    false
-}
-
-/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
-fn lint_chars_next_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
-    lint_chars_cmp_with_unwrap(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
-}
-
-/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
-fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
-    if lint_chars_cmp_with_unwrap(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
-        true
-    } else {
-        lint_chars_cmp_with_unwrap(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
-    }
-}
-
-/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, _expr: &'tcx hir::Expr, arg: &'tcx hir::Expr) {
-    if let Some((Constant::Str(r), _)) = constant(cx, cx.tables, arg) {
-        if r.len() == 1 {
-            let c = r.chars().next().unwrap();
-            let snip = snippet(cx, arg.span, "..");
-            let hint = snip.replace(
-                &format!("\"{}\"", c.escape_default()),
-                &format!("'{}'", c.escape_default()));
-            span_lint_and_sugg(
-                cx,
-                SINGLE_CHAR_PATTERN,
-                arg.span,
-                "single-character string constant used as pattern",
-                "try using a char instead",
-                hint,
-            );
-        }
-    }
-}
-
-/// Checks for the `USELESS_ASREF` lint.
-fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_ref_args: &[hir::Expr]) {
-    // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
-    // check if the call is to the actual `AsRef` or `AsMut` trait
-    if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
-        // check if the type after `as_ref` or `as_mut` is the same as before
-        let recvr = &as_ref_args[0];
-        let rcv_ty = cx.tables.expr_ty(recvr);
-        let res_ty = cx.tables.expr_ty(expr);
-        let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
-        let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
-        if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
-            span_lint_and_sugg(
-                cx,
-                USELESS_ASREF,
-                expr.span,
-                &format!("this call to `{}` does nothing", call_name),
-                "try this",
-                snippet(cx, recvr.span, "_").into_owned(),
-            );
-        }
-    }
-}
-
-/// Given a `Result<T, E>` type, return its error type (`E`).
-fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
-    if let ty::TyAdt(_, substs) = ty.sty {
-        if match_type(cx, ty, &paths::RESULT) {
-            substs.types().nth(1)
-        } else {
-            None
-        }
-    } else {
-        None
-    }
-}
-
-/// This checks whether a given type is known to implement Debug.
-fn has_debug_impl<'a, 'b>(ty: Ty<'a>, cx: &LateContext<'b, 'a>) -> bool {
-    match cx.tcx.lang_items().debug_trait() {
-        Some(debug) => implements_trait(cx, ty, debug, &[]),
-        None => false,
-    }
-}
-
-enum Convention {
-    Eq(&'static str),
-    StartsWith(&'static str),
-}
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-const CONVENTIONS: [(Convention, &[SelfKind]); 6] = [
-    (Convention::Eq("new"), &[SelfKind::No]),
-    (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
-    (Convention::StartsWith("from_"), &[SelfKind::No]),
-    (Convention::StartsWith("into_"), &[SelfKind::Value]),
-    (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
-    (Convention::StartsWith("to_"), &[SelfKind::Ref]),
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-const TRAIT_METHODS: [(&str, usize, SelfKind, OutType, &str); 30] = [
-    ("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"),
-    ("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
-    ("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
-    ("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
-    ("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
-    ("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
-    ("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
-    ("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
-    ("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
-    ("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
-    ("default", 0, SelfKind::No, OutType::Any, "std::default::Default"),
-    ("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
-    ("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
-    ("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"),
-    ("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
-    ("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
-    ("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
-    ("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"),
-    ("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
-    ("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
-    ("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
-    ("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
-    ("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"),
-    ("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"),
-    ("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
-    ("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"),
-    ("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"),
-    ("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"),
-    ("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"),
-    ("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
-];
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-const PATTERN_METHODS: [(&str, usize); 17] = [
-    ("contains", 1),
-    ("starts_with", 1),
-    ("ends_with", 1),
-    ("find", 1),
-    ("rfind", 1),
-    ("split", 1),
-    ("rsplit", 1),
-    ("split_terminator", 1),
-    ("rsplit_terminator", 1),
-    ("splitn", 2),
-    ("rsplitn", 2),
-    ("matches", 1),
-    ("rmatches", 1),
-    ("match_indices", 1),
-    ("rmatch_indices", 1),
-    ("trim_left_matches", 1),
-    ("trim_right_matches", 1),
-];
-
-
-#[derive(Clone, Copy, PartialEq, Debug)]
-enum SelfKind {
-    Value,
-    Ref,
-    RefMut,
-    No,
-}
-
-impl SelfKind {
-    fn matches(
-        self,
-        cx: &LateContext<'_, '_>,
-        ty: &hir::Ty,
-        arg: &hir::Arg,
-        self_ty: &hir::Ty,
-        allow_value_for_ref: bool,
-        generics: &hir::Generics,
-    ) -> bool {
-        // Self types in the HIR are desugared to explicit self types. So it will
-        // always be `self:
-        // SomeType`,
-        // where SomeType can be `Self` or an explicit impl self type (e.g. `Foo` if
-        // the impl is on `Foo`)
-        // Thus, we only need to test equality against the impl self type or if it is
-        // an explicit
-        // `Self`. Furthermore, the only possible types for `self: ` are `&Self`,
-        // `Self`, `&mut Self`,
-        // and `Box<Self>`, including the equivalent types with `Foo`.
-
-        let is_actually_self = |ty| is_self_ty(ty) || SpanlessEq::new(cx).eq_ty(ty, self_ty);
-        if is_self(arg) {
-            match self {
-                SelfKind::Value => is_actually_self(ty),
-                SelfKind::Ref | SelfKind::RefMut => {
-                    if allow_value_for_ref && is_actually_self(ty) {
-                        return true;
-                    }
-                    match ty.node {
-                        hir::TyKind::Rptr(_, ref mt_ty) => {
-                            let mutability_match = if self == SelfKind::Ref {
-                                mt_ty.mutbl == hir::MutImmutable
-                            } else {
-                                mt_ty.mutbl == hir::MutMutable
-                            };
-                            is_actually_self(&mt_ty.ty) && mutability_match
-                        },
-                        _ => false,
-                    }
-                },
-                _ => false,
-            }
-        } else {
-            match self {
-                SelfKind::Value => false,
-                SelfKind::Ref => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASREF_TRAIT),
-                SelfKind::RefMut => is_as_ref_or_mut_trait(ty, self_ty, generics, &paths::ASMUT_TRAIT),
-                SelfKind::No => true,
-            }
-        }
-    }
-
-    fn description(self) -> &'static str {
-        match self {
-            SelfKind::Value => "self by value",
-            SelfKind::Ref => "self by reference",
-            SelfKind::RefMut => "self by mutable reference",
-            SelfKind::No => "no self",
-        }
-    }
-}
-
-fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[&str]) -> bool {
-    single_segment_ty(ty).map_or(false, |seg| {
-        generics.params.iter().any(|param| match param.kind {
-            hir::GenericParamKind::Type { .. } => {
-                param.name.ident().name == seg.ident.name && param.bounds.iter().any(|bound| {
-                    if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
-                        let path = &ptr.trait_ref.path;
-                        match_path(path, name) && path.segments.last().map_or(false, |s| {
-                            if let Some(ref params) = s.args {
-                                if params.parenthesized {
-                                    false
-                                } else {
-                                    // FIXME(flip1995): messy, improve if there is a better option
-                                    // in the compiler
-                                    let types: Vec<_> = params.args.iter().filter_map(|arg| match arg {
-                                        hir::GenericArg::Type(ty) => Some(ty),
-                                        _ => None,
-                                    }).collect();
-                                    types.len() == 1
-                                        && (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
-                                }
-                            } else {
-                                false
-                            }
-                        })
-                    } else {
-                        false
-                    }
-                })
-            },
-            _ => false,
-        })
-    })
-}
-
-fn is_ty(ty: &hir::Ty, self_ty: &hir::Ty) -> bool {
-    match (&ty.node, &self_ty.node) {
-        (
-            &hir::TyKind::Path(hir::QPath::Resolved(_, ref ty_path)),
-            &hir::TyKind::Path(hir::QPath::Resolved(_, ref self_ty_path)),
-        ) => ty_path
-            .segments
-            .iter()
-            .map(|seg| seg.ident.name)
-            .eq(self_ty_path.segments.iter().map(|seg| seg.ident.name)),
-        _ => false,
-    }
-}
-
-fn single_segment_ty(ty: &hir::Ty) -> Option<&hir::PathSegment> {
-    if let hir::TyKind::Path(ref path) = ty.node {
-        single_segment_path(path)
-    } else {
-        None
-    }
-}
-
-impl Convention {
-    fn check(&self, other: &str) -> bool {
-        match *self {
-            Convention::Eq(this) => this == other,
-            Convention::StartsWith(this) => other.starts_with(this) && this != other,
-        }
-    }
-}
-
-impl fmt::Display for Convention {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        match *self {
-            Convention::Eq(this) => this.fmt(f),
-            Convention::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
-        }
-    }
-}
-
-#[derive(Clone, Copy)]
-enum OutType {
-    Unit,
-    Bool,
-    Any,
-    Ref,
-}
-
-impl OutType {
-    fn matches(self, cx: &LateContext<'_, '_>, ty: &hir::FunctionRetTy) -> bool {
-        let is_unit = |ty: &hir::Ty| SpanlessEq::new(cx).eq_ty_kind(&ty.node, &hir::TyKind::Tup(vec![].into()));
-        match (self, ty) {
-            (OutType::Unit, &hir::DefaultReturn(_)) => true,
-            (OutType::Unit, &hir::Return(ref ty)) if is_unit(ty) => true,
-            (OutType::Bool, &hir::Return(ref ty)) if is_bool(ty) => true,
-            (OutType::Any, &hir::Return(ref ty)) if !is_unit(ty) => true,
-            (OutType::Ref, &hir::Return(ref ty)) => matches!(ty.node, hir::TyKind::Rptr(_, _)),
-            _ => false,
-        }
-    }
-}
-
-fn is_bool(ty: &hir::Ty) -> bool {
-    if let hir::TyKind::Path(ref p) = ty.node {
-        match_qpath(p, &["bool"])
-    } else {
-        false
-    }
-}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
new file mode 100644 (file)
index 0000000..8621d11
--- /dev/null
@@ -0,0 +1,2664 @@
+mod option_map_unwrap_or;
+mod unnecessary_filter_map;
+
+use std::borrow::Cow;
+use std::fmt;
+use std::iter;
+
+use if_chain::if_chain;
+use lazy_static::lazy_static;
+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};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast;
+use syntax::source_map::{BytePos, Span};
+use syntax::symbol::{LocalInternedString, Symbol};
+
+use crate::utils::paths;
+use crate::utils::sugg;
+use crate::utils::sym;
+use crate::utils::{
+    get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
+    is_ctor_function, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path,
+    match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, remove_blocks, return_ty,
+    same_tys, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
+    span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
+};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `.unwrap()` calls on `Option`s.
+    ///
+    /// **Why is this bad?** Usually it is better to handle the `None` case, or to
+    /// at least call `.expect(_)` with a more helpful message. Still, for a lot of
+    /// quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
+    /// `Allow` by default.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.unwrap()
+    /// ```
+    pub OPTION_UNWRAP_USED,
+    restriction,
+    "using `Option.unwrap()`, which should at least get a better message using `expect()`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `.unwrap()` calls on `Result`s.
+    ///
+    /// **Why is this bad?** `result.unwrap()` will let the thread panic on `Err`
+    /// values. Normally, you want to implement more sophisticated error handling,
+    /// and propagate errors upwards with `try!`.
+    ///
+    /// Even if you want to panic on errors, not all `Error`s implement good
+    /// messages on display. Therefore, it may be beneficial to look at the places
+    /// where they may get displayed. Activate this lint to do just that.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.unwrap()
+    /// ```
+    pub RESULT_UNWRAP_USED,
+    restriction,
+    "using `Result.unwrap()`, which might be better handled"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for methods that should live in a trait
+    /// implementation of a `std` trait (see [llogiq's blog
+    /// post](http://llogiq.github.io/2015/07/30/traits.html) for further
+    /// information) instead of an inherent implementation.
+    ///
+    /// **Why is this bad?** Implementing the traits improve ergonomics for users of
+    /// the code, often with very little cost. Also people seeing a `mul(...)`
+    /// method
+    /// may expect `*` to work equally, so you should have good reason to disappoint
+    /// them.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// struct X;
+    /// impl X {
+    ///     fn add(&self, other: &X) -> X {
+    ///         ..
+    ///     }
+    /// }
+    /// ```
+    pub SHOULD_IMPLEMENT_TRAIT,
+    style,
+    "defining a method that should be implementing a std trait"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for methods with certain name prefixes and which
+    /// doesn't match how self is taken. The actual rules are:
+    ///
+    /// |Prefix |`self` taken          |
+    /// |-------|----------------------|
+    /// |`as_`  |`&self` or `&mut self`|
+    /// |`from_`| none                 |
+    /// |`into_`|`self`                |
+    /// |`is_`  |`&self` or none       |
+    /// |`to_`  |`&self`               |
+    ///
+    /// **Why is this bad?** Consistency breeds readability. If you follow the
+    /// conventions, your users won't be surprised that they, e.g., need to supply a
+    /// mutable reference to a `as_..` function.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// impl X {
+    ///     fn as_str(self) -> &str {
+    ///         ..
+    ///     }
+    /// }
+    /// ```
+    pub WRONG_SELF_CONVENTION,
+    style,
+    "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** This is the same as
+    /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
+    ///
+    /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
+    ///
+    /// **Known problems:** Actually *renaming* the function may break clients if
+    /// the function is part of the public interface. In that case, be mindful of
+    /// the stability guarantees you've given your users.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// impl X {
+    ///     pub fn as_str(self) -> &str {
+    ///         ..
+    ///     }
+    /// }
+    /// ```
+    pub WRONG_PUB_SELF_CONVENTION,
+    restriction,
+    "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `ok().expect(..)`.
+    ///
+    /// **Why is this bad?** Because you usually call `expect()` on the `Result`
+    /// directly to get a better error message.
+    ///
+    /// **Known problems:** The error type needs to implement `Debug`
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// x.ok().expect("why did I do this again?")
+    /// ```
+    pub OK_EXPECT,
+    style,
+    "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.map_or(_, _)`.
+    ///
+    /// **Known problems:** The order of the arguments is not in execution order
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.map(|a| a + 1).unwrap_or(0)
+    /// ```
+    pub OPTION_MAP_UNWRAP_OR,
+    pedantic,
+    "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.map(_).unwrap_or_else(_)`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.map_or_else(_, _)`.
+    ///
+    /// **Known problems:** The order of the arguments is not in execution order.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.map(|a| a + 1).unwrap_or_else(some_function)
+    /// ```
+    pub OPTION_MAP_UNWRAP_OR_ELSE,
+    pedantic,
+    "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `result.ok().map_or_else(_, _)`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.map(|a| a + 1).unwrap_or_else(some_function)
+    /// ```
+    pub RESULT_MAP_UNWRAP_OR_ELSE,
+    pedantic,
+    "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.map_or(None, _)`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.and_then(_)`.
+    ///
+    /// **Known problems:** The order of the arguments is not in execution order.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// opt.map_or(None, |a| a + 1)
+    /// ```
+    pub OPTION_MAP_OR_NONE,
+    style,
+    "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 `_.filter(_).next()`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.find(_)`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// iter.filter(|x| x == 0).next()
+    /// ```
+    pub FILTER_NEXT,
+    complexity,
+    "using `filter(p).next()`, which is more succinctly expressed as `.find(p)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as a
+    /// single method call.
+    ///
+    /// **Known problems:**
+    ///
+    /// **Example:**
+    /// ```rust
+    /// iter.map(|x| x.iter()).flatten()
+    /// ```
+    pub MAP_FLATTEN,
+    pedantic,
+    "using combinations of `flatten` and `map` which can usually be written as a single method call"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.filter(_).map(_)`,
+    /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as a
+    /// single method call.
+    ///
+    /// **Known problems:** Often requires a condition + Option/Iterator creation
+    /// inside the closure.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// iter.filter(|x| x == 0).map(|x| x * 2)
+    /// ```
+    pub FILTER_MAP,
+    pedantic,
+    "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as a
+    /// single method call.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    ///  (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
+    /// ```
+    /// Can be written as
+    ///
+    /// ```rust
+    ///  (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
+    /// ```
+    pub FILTER_MAP_NEXT,
+    pedantic,
+    "using combination of `filter_map` and `next` which can usually be written as a single method call"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.find(_).map(_)`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as a
+    /// single method call.
+    ///
+    /// **Known problems:** Often requires a condition + Option/Iterator creation
+    /// inside the closure.
+    ///
+    /// **Example:**
+    /// ```rust
+    ///  (0..3).find(|x| x == 2).map(|x| x * 2);
+    /// ```
+    /// Can be written as
+    /// ```rust
+    ///  (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None });
+    /// ```
+    pub FIND_MAP,
+    pedantic,
+    "using a combination of `find` and `map` can usually be written as a single method call"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for an iterator search (such as `find()`,
+    /// `position()`, or `rposition()`) followed by a call to `is_some()`.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.any(_)`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// iter.find(|x| x == 0).is_some()
+    /// ```
+    pub SEARCH_IS_SOME,
+    complexity,
+    "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
+    /// if it starts with a given char.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.starts_with(_)`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// name.chars().next() == Some('_')
+    /// ```
+    pub CHARS_NEXT_CMP,
+    complexity,
+    "using `.chars().next()` to check if a string starts with a char"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
+    /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
+    /// `unwrap_or_default` instead.
+    ///
+    /// **Why is this bad?** The function will always be called and potentially
+    /// allocate an object acting as the default.
+    ///
+    /// **Known problems:** If the function has side-effects, not calling it will
+    /// change the semantic of the program, but you shouldn't rely on that anyway.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// foo.unwrap_or(String::new())
+    /// ```
+    /// this can instead be written:
+    /// ```rust
+    /// foo.unwrap_or_else(String::new)
+    /// ```
+    /// or
+    /// ```rust
+    /// foo.unwrap_or_default()
+    /// ```
+    pub OR_FUN_CALL,
+    perf,
+    "using any `*or` method with a function call, which suggests `*or_else`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
+    /// etc., and suggests to use `unwrap_or_else` instead
+    ///
+    /// **Why is this bad?** The function will always be called.
+    ///
+    /// **Known problems:** If the function has side-effects, not calling it will
+    /// change the semantics of the program, but you shouldn't rely on that anyway.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// foo.expect(&format!("Err {}: {}", err_code, err_msg))
+    /// ```
+    /// or
+    /// ```rust
+    /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str())
+    /// ```
+    /// this can instead be written:
+    /// ```rust
+    /// foo.unwrap_or_else(|_| panic!("Err {}: {}", err_code, err_msg))
+    /// ```
+    pub EXPECT_FUN_CALL,
+    perf,
+    "using any `expect` method with a function call"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.clone()` on a `Copy` type.
+    ///
+    /// **Why is this bad?** The only reason `Copy` types implement `Clone` is for
+    /// generics, not for using the `clone` method on a concrete type.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// 42u64.clone()
+    /// ```
+    pub CLONE_ON_COPY,
+    complexity,
+    "using `clone` on a `Copy` type"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.clone()` on a ref-counted pointer,
+    /// (`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
+    /// function syntax instead (e.g., `Rc::clone(foo)`).
+    ///
+    /// **Why is this bad?** Calling '.clone()' on an Rc, Arc, or Weak
+    /// can obscure the fact that only the pointer is being cloned, not the underlying
+    /// data.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.clone()
+    /// ```
+    pub CLONE_ON_REF_PTR,
+    restriction,
+    "using 'clone' on a ref-counted pointer"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.clone()` on an `&&T`.
+    ///
+    /// **Why is this bad?** Cloning an `&&T` copies the inner `&T`, instead of
+    /// cloning the underlying `T`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn main() {
+    ///     let x = vec![1];
+    ///     let y = &&x;
+    ///     let z = y.clone();
+    ///     println!("{:p} {:p}", *y, z); // prints out the same pointer
+    /// }
+    /// ```
+    pub CLONE_DOUBLE_REF,
+    correctness,
+    "using `clone` on `&&T`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `new` not returning `Self`.
+    ///
+    /// **Why is this bad?** As a convention, `new` methods are used to make a new
+    /// instance of a type.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// impl Foo {
+    ///     fn new(..) -> NotAFoo {
+    ///     }
+    /// }
+    /// ```
+    pub NEW_RET_NO_SELF,
+    style,
+    "not returning `Self` in a `new` method"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for string methods that receive a single-character
+    /// `str` as an argument, e.g., `_.split("x")`.
+    ///
+    /// **Why is this bad?** Performing these methods using a `char` is faster than
+    /// using a `str`.
+    ///
+    /// **Known problems:** Does not catch multi-byte unicode characters.
+    ///
+    /// **Example:**
+    /// `_.split("x")` could be `_.split('x')`
+    pub SINGLE_CHAR_PATTERN,
+    perf,
+    "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for getting the inner pointer of a temporary
+    /// `CString`.
+    ///
+    /// **Why is this bad?** The inner pointer of a `CString` is only valid as long
+    /// as the `CString` is alive.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// let c_str = CString::new("foo").unwrap().as_ptr();
+    /// unsafe {
+    ///     call_some_ffi_func(c_str);
+    /// }
+    /// ```
+    /// Here `c_str` point to a freed address. The correct use would be:
+    /// ```rust,ignore
+    /// let c_str = CString::new("foo").unwrap();
+    /// unsafe {
+    ///     call_some_ffi_func(c_str.as_ptr());
+    /// }
+    /// ```
+    pub TEMPORARY_CSTRING_AS_PTR,
+    correctness,
+    "getting the inner pointer of a temporary `CString`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for use of `.iter().nth()` (and the related
+    /// `.iter_mut().nth()`) on standard library types with O(1) element access.
+    ///
+    /// **Why is this bad?** `.get()` and `.get_mut()` are more efficient and more
+    /// readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let some_vec = vec![0, 1, 2, 3];
+    /// let bad_vec = some_vec.iter().nth(3);
+    /// let bad_slice = &some_vec[..].iter().nth(3);
+    /// ```
+    /// The correct use would be:
+    /// ```rust
+    /// let some_vec = vec![0, 1, 2, 3];
+    /// let bad_vec = some_vec.get(3);
+    /// let bad_slice = &some_vec[..].get(3);
+    /// ```
+    pub ITER_NTH,
+    perf,
+    "using `.iter().nth()` on a standard library type with O(1) element access"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for use of `.skip(x).next()` on iterators.
+    ///
+    /// **Why is this bad?** `.nth(x)` is cleaner
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let some_vec = vec![0, 1, 2, 3];
+    /// let bad_vec = some_vec.iter().skip(3).next();
+    /// let bad_slice = &some_vec[..].iter().skip(3).next();
+    /// ```
+    /// The correct use would be:
+    /// ```rust
+    /// let some_vec = vec![0, 1, 2, 3];
+    /// let bad_vec = some_vec.iter().nth(3);
+    /// let bad_slice = &some_vec[..].iter().nth(3);
+    /// ```
+    pub ITER_SKIP_NEXT,
+    style,
+    "using `.skip(x).next()` on an iterator"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for use of `.get().unwrap()` (or
+    /// `.get_mut().unwrap`) on a standard library type which implements `Index`
+    ///
+    /// **Why is this bad?** Using the Index trait (`[]`) is more clear and more
+    /// concise.
+    ///
+    /// **Known problems:** Not a replacement for error handling: Using either
+    /// `.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
+    /// if the value being accessed is `None`. If the use of `.get().unwrap()` is a
+    /// temporary placeholder for dealing with the `Option` type, then this does
+    /// not mitigate the need for error handling. If there is a chance that `.get()`
+    /// will be `None` in your program, then it is advisable that the `None` case
+    /// is handled in a future refactor instead of using `.unwrap()` or the Index
+    /// trait.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut some_vec = vec![0, 1, 2, 3];
+    /// let last = some_vec.get(3).unwrap();
+    /// *some_vec.get_mut(0).unwrap() = 1;
+    /// ```
+    /// The correct use would be:
+    /// ```rust
+    /// let mut some_vec = vec![0, 1, 2, 3];
+    /// let last = some_vec[3];
+    /// some_vec[0] = 1;
+    /// ```
+    pub GET_UNWRAP,
+    restriction,
+    "using `.get().unwrap()` or `.get_mut().unwrap()` when using `[]` would work instead"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
+    /// `&str` or `String`.
+    ///
+    /// **Why is this bad?** `.push_str(s)` is clearer
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let abc = "abc";
+    /// let def = String::from("def");
+    /// let mut s = String::new();
+    /// s.extend(abc.chars());
+    /// s.extend(def.chars());
+    /// ```
+    /// The correct use would be:
+    /// ```rust
+    /// let abc = "abc";
+    /// let def = String::from("def");
+    /// let mut s = String::new();
+    /// s.push_str(abc);
+    /// s.push_str(&def);
+    /// ```
+    pub STRING_EXTEND_CHARS,
+    style,
+    "using `x.extend(s.chars())` where s is a `&str` or `String`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for the use of `.cloned().collect()` on slice to
+    /// create a `Vec`.
+    ///
+    /// **Why is this bad?** `.to_vec()` is clearer
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let s = [1, 2, 3, 4, 5];
+    /// let s2: Vec<isize> = s[..].iter().cloned().collect();
+    /// ```
+    /// The better use would be:
+    /// ```rust
+    /// let s = [1, 2, 3, 4, 5];
+    /// let s2: Vec<isize> = s.to_vec();
+    /// ```
+    pub ITER_CLONED_COLLECT,
+    style,
+    "using `.cloned().collect()` on slice to create a `Vec`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.chars().last()` or
+    /// `.chars().next_back()` on a `str` to check if it ends with a given char.
+    ///
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.ends_with(_)`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-')
+    /// ```
+    pub CHARS_LAST_CMP,
+    style,
+    "using `.chars().last()` or `.chars().next_back()` to check if a string ends with a char"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `.as_ref()` or `.as_mut()` where the
+    /// types before and after the call are the same.
+    ///
+    /// **Why is this bad?** The call is unnecessary.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: &[i32] = &[1, 2, 3, 4, 5];
+    /// do_stuff(x.as_ref());
+    /// ```
+    /// The correct use would be:
+    /// ```rust
+    /// let x: &[i32] = &[1, 2, 3, 4, 5];
+    /// do_stuff(x);
+    /// ```
+    pub USELESS_ASREF,
+    complexity,
+    "using `as_ref` where the types before and after the call are the same"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for using `fold` when a more succinct alternative exists.
+    /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
+    /// `sum` or `product`.
+    ///
+    /// **Why is this bad?** Readability.
+    ///
+    /// **Known problems:** False positive in pattern guards. Will be resolved once
+    /// non-lexical lifetimes are stable.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+    /// ```
+    /// This could be written as:
+    /// ```rust
+    /// let _ = (0..3).any(|x| x > 2);
+    /// ```
+    pub UNNECESSARY_FOLD,
+    style,
+    "using `fold` when a more succinct alternative exists"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
+    /// More specifically it checks if the closure provided is only performing one of the
+    /// filter or map operations and suggests the appropriate option.
+    ///
+    /// **Why is this bad?** Complexity. The intent is also clearer if only a single
+    /// operation is being performed.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
+    /// ```
+    /// As there is no transformation of the argument this could be written as:
+    /// ```rust
+    /// let _ = (0..3).filter(|&x| x > 2);
+    /// ```
+    ///
+    /// ```rust
+    /// let _ = (0..4).filter_map(i32::checked_abs);
+    /// ```
+    /// As there is no conditional check on the argument this could be written as:
+    /// ```rust
+    /// let _ = (0..4).map(i32::checked_abs);
+    /// ```
+    pub UNNECESSARY_FILTER_MAP,
+    complexity,
+    "using `filter_map` when a more succinct alternative exists"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `into_iter` calls on types which should be replaced by `iter` or
+    /// `iter_mut`.
+    ///
+    /// **Why is this bad?** Arrays and `PathBuf` do not yet have an `into_iter` method which move out
+    /// their content into an iterator. Auto-referencing resolves the `into_iter` call to its reference
+    /// instead, like `<&[T; N] as IntoIterator>::into_iter`, which just iterates over item references
+    /// like calling `iter` would. Furthermore, when the standard library actually
+    /// [implements the `into_iter` method](https://github.com/rust-lang/rust/issues/25725) which moves
+    /// the content out of the array, the original use of `into_iter` got inferred with the wrong type
+    /// and the code will be broken.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let _ = [1, 2, 3].into_iter().map(|x| *x).collect::<Vec<u32>>();
+    /// ```
+    pub INTO_ITER_ON_ARRAY,
+    correctness,
+    "using `.into_iter()` on an array"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `into_iter` calls on references which should be replaced by `iter`
+    /// or `iter_mut`.
+    ///
+    /// **Why is this bad?** Readability. Calling `into_iter` on a reference will not move out its
+    /// content into the resulting iterator, which is confusing. It is better just call `iter` or
+    /// `iter_mut` directly.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let _ = (&vec![3, 4, 5]).into_iter();
+    /// ```
+    pub INTO_ITER_ON_REF,
+    style,
+    "using `.into_iter()` on a reference"
+}
+
+declare_lint_pass!(Methods => [
+    OPTION_UNWRAP_USED,
+    RESULT_UNWRAP_USED,
+    SHOULD_IMPLEMENT_TRAIT,
+    WRONG_SELF_CONVENTION,
+    WRONG_PUB_SELF_CONVENTION,
+    OK_EXPECT,
+    OPTION_MAP_UNWRAP_OR,
+    OPTION_MAP_UNWRAP_OR_ELSE,
+    RESULT_MAP_UNWRAP_OR_ELSE,
+    OPTION_MAP_OR_NONE,
+    OR_FUN_CALL,
+    EXPECT_FUN_CALL,
+    CHARS_NEXT_CMP,
+    CHARS_LAST_CMP,
+    CLONE_ON_COPY,
+    CLONE_ON_REF_PTR,
+    CLONE_DOUBLE_REF,
+    NEW_RET_NO_SELF,
+    SINGLE_CHAR_PATTERN,
+    SEARCH_IS_SOME,
+    TEMPORARY_CSTRING_AS_PTR,
+    FILTER_NEXT,
+    FILTER_MAP,
+    FILTER_MAP_NEXT,
+    FIND_MAP,
+    MAP_FLATTEN,
+    ITER_NTH,
+    ITER_SKIP_NEXT,
+    GET_UNWRAP,
+    STRING_EXTEND_CHARS,
+    ITER_CLONED_COLLECT,
+    USELESS_ASREF,
+    UNNECESSARY_FOLD,
+    UNNECESSARY_FILTER_MAP,
+    INTO_ITER_ON_ARRAY,
+    INTO_ITER_ON_REF,
+]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
+    #[allow(clippy::cognitive_complexity)]
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
+        if in_macro(expr.span) {
+            return;
+        }
+
+        let (method_names, arg_lists) = method_calls(expr, 2);
+        let method_names: Vec<LocalInternedString> = method_names.iter().map(|s| s.as_str()).collect();
+        let method_names: Vec<&str> = method_names.iter().map(std::convert::AsRef::as_ref).collect();
+
+        match method_names.as_slice() {
+            ["unwrap", "get"] => lint_get_unwrap(cx, expr, arg_lists[1], false),
+            ["unwrap", "get_mut"] => lint_get_unwrap(cx, expr, arg_lists[1], true),
+            ["unwrap", ..] => lint_unwrap(cx, expr, arg_lists[0]),
+            ["expect", "ok"] => lint_ok_expect(cx, expr, arg_lists[1]),
+            ["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]),
+            ["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]),
+            ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
+            ["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
+            ["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
+            ["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
+            ["flatten", "map"] => lint_map_flatten(cx, expr, arg_lists[1]),
+            ["is_some", "find"] => lint_search_is_some(cx, expr, "find", arg_lists[1], arg_lists[0]),
+            ["is_some", "position"] => lint_search_is_some(cx, expr, "position", arg_lists[1], arg_lists[0]),
+            ["is_some", "rposition"] => lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0]),
+            ["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
+            ["as_ptr", "unwrap"] => lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]),
+            ["nth", "iter"] => lint_iter_nth(cx, expr, arg_lists[1], false),
+            ["nth", "iter_mut"] => lint_iter_nth(cx, expr, arg_lists[1], true),
+            ["next", "skip"] => lint_iter_skip_next(cx, expr),
+            ["collect", "cloned"] => lint_iter_cloned_collect(cx, expr, arg_lists[1]),
+            ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]),
+            ["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]),
+            _ => {},
+        }
+
+        match expr.node {
+            hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => {
+                lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
+                lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
+
+                let self_ty = cx.tables.expr_ty_adjusted(&args[0]);
+                if args.len() == 1 && method_call.ident.name == *sym::clone {
+                    lint_clone_on_copy(cx, expr, &args[0], self_ty);
+                    lint_clone_on_ref_ptr(cx, expr, &args[0]);
+                }
+
+                match self_ty.sty {
+                    ty::Ref(_, ty, _) if ty.sty == ty::Str => {
+                        for &(method, pos) in PATTERN_METHODS.iter() {
+                            if method_call.ident.name == method && args.len() > pos {
+                                lint_single_char_pattern(cx, expr, &args[pos]);
+                            }
+                        }
+                    },
+                    ty::Ref(..) if method_call.ident.name == *sym::into_iter => {
+                        lint_into_iter(cx, expr, self_ty, *method_span);
+                    },
+                    _ => (),
+                }
+            },
+            hir::ExprKind::Binary(op, ref lhs, ref rhs)
+                if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
+            {
+                let mut info = BinaryExprInfo {
+                    expr,
+                    chain: lhs,
+                    other: rhs,
+                    eq: op.node == hir::BinOpKind::Eq,
+                };
+                lint_binary_expr_with_method_call(cx, &mut info);
+            }
+            _ => (),
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, implitem: &'tcx hir::ImplItem) {
+        if in_external_macro(cx.sess(), implitem.span) {
+            return;
+        }
+        let name = implitem.ident.name;
+        let parent = cx.tcx.hir().get_parent_item(implitem.hir_id);
+        let item = cx.tcx.hir().expect_item_by_hir_id(parent);
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
+        let ty = cx.tcx.type_of(def_id);
+        if_chain! {
+            if let hir::ImplItemKind::Method(ref sig, id) = implitem.node;
+            if let Some(first_arg_ty) = sig.decl.inputs.get(0);
+            if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
+            if let hir::ItemKind::Impl(_, _, _, _, None, ref self_ty, _) = item.node;
+            then {
+                if cx.access_levels.is_exported(implitem.hir_id) {
+                // check missing trait implementations
+                    for &(method_name, n_args, self_kind, out_type, trait_name) in TRAIT_METHODS.iter() {
+                        if name == method_name &&
+                        sig.decl.inputs.len() == n_args &&
+                        out_type.matches(cx, &sig.decl.output) &&
+                        self_kind.matches(cx, first_arg_ty, first_arg, self_ty, false, &implitem.generics) {
+                            span_lint(cx, SHOULD_IMPLEMENT_TRAIT, implitem.span, &format!(
+                                "defining a method called `{}` on this type; consider implementing \
+                                the `{}` trait or choosing a less ambiguous name", name, trait_name));
+                        }
+                    }
+                }
+
+                // check conventions w.r.t. conversion method names and predicates
+                let is_copy = is_copy(cx, ty);
+                for &(ref conv, self_kinds) in &CONVENTIONS {
+                    if conv.check(&name.as_str()) {
+                        if !self_kinds
+                                .iter()
+                                .any(|k| k.matches(cx, first_arg_ty, first_arg, self_ty, is_copy, &implitem.generics)) {
+                            let lint = if item.vis.node.is_pub() {
+                                WRONG_PUB_SELF_CONVENTION
+                            } else {
+                                WRONG_SELF_CONVENTION
+                            };
+                            span_lint(cx,
+                                      lint,
+                                      first_arg.pat.span,
+                                      &format!("methods called `{}` usually take {}; consider choosing a less \
+                                                ambiguous name",
+                                               conv,
+                                               &self_kinds.iter()
+                                                          .map(|k| k.description())
+                                                          .collect::<Vec<_>>()
+                                                          .join(" or ")));
+                        }
+
+                        // Only check the first convention to match (CONVENTIONS should be listed from most to least
+                        // specific)
+                        break;
+                    }
+                }
+            }
+        }
+
+        if let hir::ImplItemKind::Method(_, _) = implitem.node {
+            let ret_ty = return_ty(cx, implitem.hir_id);
+
+            // walk the return type and check for Self (this does not check associated types)
+            for inner_type in ret_ty.walk() {
+                if same_tys(cx, ty, inner_type) {
+                    return;
+                }
+            }
+
+            // if return type is impl trait, check the associated types
+            if let ty::Opaque(def_id, _) = ret_ty.sty {
+                // one of the associated types must be Self
+                for predicate in &cx.tcx.predicates_of(def_id).predicates {
+                    match predicate {
+                        (Predicate::Projection(poly_projection_predicate), _) => {
+                            let binder = poly_projection_predicate.ty();
+                            let associated_type = binder.skip_binder();
+                            let associated_type_is_self_type = same_tys(cx, ty, associated_type);
+
+                            // if the associated type is self, early return and do not trigger lint
+                            if associated_type_is_self_type {
+                                return;
+                            }
+                        },
+                        (_, _) => {},
+                    }
+                }
+            }
+
+            if name == *sym::new && !same_tys(cx, ret_ty, ty) {
+                span_lint(
+                    cx,
+                    NEW_RET_NO_SELF,
+                    implitem.span,
+                    "methods called `new` usually return `Self`",
+                );
+            }
+        }
+    }
+}
+
+/// Checks for the `OR_FUN_CALL` lint.
+#[allow(clippy::too_many_lines)]
+fn lint_or_fun_call<'a, 'tcx: 'a>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &hir::Expr,
+    method_span: Span,
+    name: &str,
+    args: &'tcx [hir::Expr],
+) {
+    // Searches an expression for method calls or function calls that aren't ctors
+    struct FunCallFinder<'a, 'tcx: 'a> {
+        cx: &'a LateContext<'a, 'tcx>,
+        found: bool,
+    }
+
+    impl<'a, 'tcx> intravisit::Visitor<'tcx> for FunCallFinder<'a, 'tcx> {
+        fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+            let call_found = match &expr.node {
+                // ignore enum and struct constructors
+                hir::ExprKind::Call(..) => !is_ctor_function(self.cx, expr),
+                hir::ExprKind::MethodCall(..) => true,
+                _ => false,
+            };
+
+            if call_found {
+                // don't lint for constant values
+                let owner_def = self.cx.tcx.hir().get_parent_did_by_hir_id(expr.hir_id);
+                let promotable = self
+                    .cx
+                    .tcx
+                    .rvalue_promotable_map(owner_def)
+                    .contains(&expr.hir_id.local_id);
+                if !promotable {
+                    self.found |= true;
+                }
+            }
+
+            if !self.found {
+                intravisit::walk_expr(self, expr);
+            }
+        }
+
+        fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
+            intravisit::NestedVisitorMap::None
+        }
+    }
+
+    /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+    fn check_unwrap_or_default(
+        cx: &LateContext<'_, '_>,
+        name: &str,
+        fun: &hir::Expr,
+        self_expr: &hir::Expr,
+        arg: &hir::Expr,
+        or_has_args: bool,
+        span: Span,
+    ) -> bool {
+        if or_has_args {
+            return false;
+        }
+
+        if name == "unwrap_or" {
+            if let hir::ExprKind::Path(ref qpath) = fun.node {
+                let path = &*last_path_segment(qpath).ident.as_str();
+
+                if ["default", "new"].contains(&path) {
+                    let arg_ty = cx.tables.expr_ty(arg);
+                    let default_trait_id = if let Some(default_trait_id) = get_trait_def_id(cx, &*paths::DEFAULT_TRAIT)
+                    {
+                        default_trait_id
+                    } else {
+                        return false;
+                    };
+
+                    if implements_trait(cx, arg_ty, default_trait_id, &[]) {
+                        let mut applicability = Applicability::MachineApplicable;
+                        span_lint_and_sugg(
+                            cx,
+                            OR_FUN_CALL,
+                            span,
+                            &format!("use of `{}` followed by a call to `{}`", name, path),
+                            "try this",
+                            format!(
+                                "{}.unwrap_or_default()",
+                                snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
+                            ),
+                            applicability,
+                        );
+                        return true;
+                    }
+                }
+            }
+        }
+
+        false
+    }
+
+    /// Checks for `*or(foo())`.
+    #[allow(clippy::too_many_arguments)]
+    fn check_general_case<'a, 'tcx: 'a>(
+        cx: &LateContext<'a, 'tcx>,
+        name: &str,
+        method_span: Span,
+        fun_span: Span,
+        self_expr: &hir::Expr,
+        arg: &'tcx hir::Expr,
+        or_has_args: bool,
+        span: Span,
+    ) {
+        // (path, fn_has_argument, methods, suffix)
+        let know_types: &[(&[_], _, &[_], _)] = &[
+            (&*paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
+            (&*paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
+            (&*paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
+            (&*paths::RESULT, true, &["or", "unwrap_or"], "else"),
+        ];
+
+        // early check if the name is one we care about
+        if know_types.iter().all(|k| !k.2.contains(&name)) {
+            return;
+        }
+
+        let mut finder = FunCallFinder { cx: &cx, found: false };
+        finder.visit_expr(&arg);
+        if !finder.found {
+            return;
+        }
+
+        let self_ty = cx.tables.expr_ty(self_expr);
+
+        let (fn_has_arguments, poss, suffix) = if let Some(&(_, fn_has_arguments, poss, suffix)) =
+            know_types.iter().find(|&&i| match_type(cx, self_ty, i.0))
+        {
+            (fn_has_arguments, poss, suffix)
+        } else {
+            return;
+        };
+
+        if !poss.contains(&name) {
+            return;
+        }
+
+        let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) {
+            (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
+            (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(),
+            (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."),
+        };
+        let span_replace_word = method_span.with_hi(span.hi());
+        span_lint_and_sugg(
+            cx,
+            OR_FUN_CALL,
+            span_replace_word,
+            &format!("use of `{}` followed by a function call", name),
+            "try this",
+            format!("{}_{}({})", name, suffix, sugg),
+            Applicability::HasPlaceholders,
+        );
+    }
+
+    if args.len() == 2 {
+        match args[1].node {
+            hir::ExprKind::Call(ref fun, ref or_args) => {
+                let or_has_args = !or_args.is_empty();
+                if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
+                    check_general_case(
+                        cx,
+                        name,
+                        method_span,
+                        fun.span,
+                        &args[0],
+                        &args[1],
+                        or_has_args,
+                        expr.span,
+                    );
+                }
+            },
+            hir::ExprKind::MethodCall(_, span, ref or_args) => check_general_case(
+                cx,
+                name,
+                method_span,
+                span,
+                &args[0],
+                &args[1],
+                !or_args.is_empty(),
+                expr.span,
+            ),
+            _ => {},
+        }
+    }
+}
+
+/// Checks for the `EXPECT_FUN_CALL` lint.
+#[allow(clippy::too_many_lines)]
+fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
+    // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
+    // `&str`
+    fn get_arg_root<'a>(cx: &LateContext<'_, '_>, arg: &'a hir::Expr) -> &'a hir::Expr {
+        let mut arg_root = arg;
+        loop {
+            arg_root = match &arg_root.node {
+                hir::ExprKind::AddrOf(_, expr) => expr,
+                hir::ExprKind::MethodCall(method_name, _, call_args) => {
+                    if call_args.len() == 1
+                        && (method_name.ident.name == *sym::as_str || method_name.ident.name == *sym::as_ref)
+                        && {
+                            let arg_type = cx.tables.expr_ty(&call_args[0]);
+                            let base_type = walk_ptrs_ty(arg_type);
+                            base_type.sty == ty::Str || match_type(cx, base_type, &*paths::STRING)
+                        }
+                    {
+                        &call_args[0]
+                    } else {
+                        break;
+                    }
+                },
+                _ => break,
+            };
+        }
+        arg_root
+    }
+
+    // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
+    // converted to string.
+    fn requires_to_string(cx: &LateContext<'_, '_>, arg: &hir::Expr) -> bool {
+        let arg_ty = cx.tables.expr_ty(arg);
+        if match_type(cx, arg_ty, &*paths::STRING) {
+            return false;
+        }
+        if let ty::Ref(ty::ReStatic, ty, ..) = arg_ty.sty {
+            if ty.sty == ty::Str {
+                return false;
+            }
+        };
+        true
+    }
+
+    fn generate_format_arg_snippet(
+        cx: &LateContext<'_, '_>,
+        a: &hir::Expr,
+        applicability: &mut Applicability,
+    ) -> Vec<String> {
+        if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node {
+            if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node {
+                if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node {
+                    return format_arg_expr_tup
+                        .iter()
+                        .map(|a| snippet_with_applicability(cx, a.span, "..", applicability).into_owned())
+                        .collect();
+                }
+            }
+        };
+
+        unreachable!()
+    }
+
+    fn is_call(node: &hir::ExprKind) -> bool {
+        match node {
+            hir::ExprKind::AddrOf(_, expr) => {
+                is_call(&expr.node)
+            },
+            hir::ExprKind::Call(..)
+            | hir::ExprKind::MethodCall(..)
+            // These variants are debatable or require further examination
+            | hir::ExprKind::Match(..)
+            | hir::ExprKind::Block{ .. } => true,
+            _ => false,
+        }
+    }
+
+    if args.len() != 2 || name != "expect" || !is_call(&args[1].node) {
+        return;
+    }
+
+    let receiver_type = cx.tables.expr_ty(&args[0]);
+    let closure_args = if match_type(cx, receiver_type, &*paths::OPTION) {
+        "||"
+    } else if match_type(cx, receiver_type, &*paths::RESULT) {
+        "|_|"
+    } else {
+        return;
+    };
+
+    let arg_root = get_arg_root(cx, &args[1]);
+
+    let span_replace_word = method_span.with_hi(expr.span.hi());
+
+    let mut applicability = Applicability::MachineApplicable;
+
+    //Special handling for `format!` as arg_root
+    if let hir::ExprKind::Call(ref inner_fun, ref inner_args) = arg_root.node {
+        if is_expn_of(inner_fun.span, *sym::format).is_some() && inner_args.len() == 1 {
+            if let hir::ExprKind::Call(_, format_args) = &inner_args[0].node {
+                let fmt_spec = &format_args[0];
+                let fmt_args = &format_args[1];
+
+                let mut args = vec![snippet(cx, fmt_spec.span, "..").into_owned()];
+
+                args.extend(generate_format_arg_snippet(cx, fmt_args, &mut applicability));
+
+                let sugg = args.join(", ");
+
+                span_lint_and_sugg(
+                    cx,
+                    EXPECT_FUN_CALL,
+                    span_replace_word,
+                    &format!("use of `{}` followed by a function call", name),
+                    "try this",
+                    format!("unwrap_or_else({} panic!({}))", closure_args, sugg),
+                    applicability,
+                );
+
+                return;
+            }
+        }
+    }
+
+    let mut arg_root_snippet: Cow<'_, _> = snippet_with_applicability(cx, arg_root.span, "..", &mut applicability);
+    if requires_to_string(cx, arg_root) {
+        arg_root_snippet.to_mut().push_str(".to_string()");
+    }
+
+    span_lint_and_sugg(
+        cx,
+        EXPECT_FUN_CALL,
+        span_replace_word,
+        &format!("use of `{}` followed by a function call", name),
+        "try this",
+        format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet),
+        applicability,
+    );
+}
+
+/// Checks for the `CLONE_ON_COPY` lint.
+fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr, arg_ty: Ty<'_>) {
+    let ty = cx.tables.expr_ty(expr);
+    if let ty::Ref(_, inner, _) = arg_ty.sty {
+        if let ty::Ref(_, innermost, _) = inner.sty {
+            span_lint_and_then(
+                cx,
+                CLONE_DOUBLE_REF,
+                expr.span,
+                "using `clone` on a double-reference; \
+                 this will copy the reference instead of cloning the inner type",
+                |db| {
+                    if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
+                        let mut ty = innermost;
+                        let mut n = 0;
+                        while let ty::Ref(_, inner, _) = ty.sty {
+                            ty = inner;
+                            n += 1;
+                        }
+                        let refs: String = iter::repeat('&').take(n + 1).collect();
+                        let derefs: String = iter::repeat('*').take(n).collect();
+                        let explicit = format!("{}{}::clone({})", refs, ty, snip);
+                        db.span_suggestion(
+                            expr.span,
+                            "try dereferencing it",
+                            format!("{}({}{}).clone()", refs, derefs, snip.deref()),
+                            Applicability::MaybeIncorrect,
+                        );
+                        db.span_suggestion(
+                            expr.span,
+                            "or try being explicit about what type to clone",
+                            explicit,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                },
+            );
+            return; // don't report clone_on_copy
+        }
+    }
+
+    if is_copy(cx, ty) {
+        let snip;
+        if let Some(snippet) = sugg::Sugg::hir_opt(cx, arg) {
+            // 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_by_hir_id(expr.hir_id);
+                match cx.tcx.hir().get_by_hir_id(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)
+                    .iter()
+                    .filter(|adj| {
+                        if let ty::adjustment::Adjust::Deref(_) = adj.kind {
+                            true
+                        } else {
+                            false
+                        }
+                    })
+                    .count();
+                let derefs: String = iter::repeat('*').take(deref_count).collect();
+                snip = Some(("try dereferencing it", format!("{}{}", derefs, snippet)));
+            }
+        } else {
+            snip = None;
+        }
+        span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| {
+            if let Some((text, snip)) = snip {
+                db.span_suggestion(expr.span, text, snip, Applicability::Unspecified);
+            }
+        });
+    }
+}
+
+fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Expr) {
+    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
+
+    if let ty::Adt(_, subst) = obj_ty.sty {
+        let caller_type = if match_type(cx, obj_ty, &*paths::RC) {
+            "Rc"
+        } else if match_type(cx, obj_ty, &*paths::ARC) {
+            "Arc"
+        } else if match_type(cx, obj_ty, &*paths::WEAK_RC) || match_type(cx, obj_ty, &*paths::WEAK_ARC) {
+            "Weak"
+        } else {
+            return;
+        };
+
+        span_lint_and_sugg(
+            cx,
+            CLONE_ON_REF_PTR,
+            expr.span,
+            "using '.clone()' on a ref-counted pointer",
+            "try this",
+            format!(
+                "{}::<{}>::clone(&{})",
+                caller_type,
+                subst.type_at(0),
+                snippet(cx, arg.span, "_")
+            ),
+            Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
+        );
+    }
+}
+
+fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
+    let arg = &args[1];
+    if let Some(arglists) = method_chain_args(arg, &[*sym::chars]) {
+        let target = &arglists[0][0];
+        let self_ty = walk_ptrs_ty(cx.tables.expr_ty(target));
+        let ref_str = if self_ty.sty == ty::Str {
+            ""
+        } else if match_type(cx, self_ty, &*paths::STRING) {
+            "&"
+        } else {
+            return;
+        };
+
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            STRING_EXTEND_CHARS,
+            expr.span,
+            "calling `.extend(_.chars())`",
+            "try this",
+            format!(
+                "{}.push_str({}{})",
+                snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
+                ref_str,
+                snippet_with_applicability(cx, target.span, "_", &mut applicability)
+            ),
+            applicability,
+        );
+    }
+}
+
+fn lint_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
+    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+    if match_type(cx, obj_ty, &*paths::STRING) {
+        lint_string_extend(cx, expr, args);
+    }
+}
+
+fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, new: &hir::Expr, unwrap: &hir::Expr) {
+    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);
+        then {
+            span_lint_and_then(
+                cx,
+                TEMPORARY_CSTRING_AS_PTR,
+                expr.span,
+                "you are getting the inner pointer of a temporary `CString`",
+                |db| {
+                    db.note("that pointer will be invalid outside this expression");
+                    db.span_help(unwrap.span, "assign the `CString` to a variable to extend its lifetime");
+                });
+        }
+    }
+}
+
+fn lint_iter_cloned_collect<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr]) {
+    if match_type(cx, cx.tables.expr_ty(expr), &*paths::VEC) {
+        if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])) {
+            if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()) {
+                span_lint_and_sugg(
+                    cx,
+                    ITER_CLONED_COLLECT,
+                    to_replace,
+                    "called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and \
+                     more readable",
+                    "try",
+                    ".to_vec()".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
+fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: &[hir::Expr]) {
+    fn check_fold_with_op(
+        cx: &LateContext<'_, '_>,
+        fold_args: &[hir::Expr],
+        op: hir::BinOpKind,
+        replacement_method_name: &str,
+        replacement_has_args: bool,
+    ) {
+        if_chain! {
+            // Extract the body of the closure passed to fold
+            if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].node;
+            let closure_body = cx.tcx.hir().body(body_id);
+            let closure_expr = remove_blocks(&closure_body.value);
+
+            // Check if the closure body is of the form `acc <op> some_expr(x)`
+            if let hir::ExprKind::Binary(ref bin_op, ref left_expr, ref right_expr) = closure_expr.node;
+            if bin_op.node == op;
+
+            // Extract the names of the two arguments to the closure
+            if let Some(first_arg_ident) = get_arg_name(&closure_body.arguments[0].pat);
+            if let Some(second_arg_ident) = get_arg_name(&closure_body.arguments[1].pat);
+
+            if match_var(&*left_expr, first_arg_ident);
+            if replacement_has_args || match_var(&*right_expr, second_arg_ident);
+
+            then {
+                // Span containing `.fold(...)`
+                let next_point = cx.sess().source_map().next_point(fold_args[0].span);
+                let fold_span = next_point.with_hi(fold_args[2].span.hi() + BytePos(1));
+
+                let mut applicability = Applicability::MachineApplicable;
+                let sugg = if replacement_has_args {
+                    format!(
+                        ".{replacement}(|{s}| {r})",
+                        replacement = replacement_method_name,
+                        s = second_arg_ident,
+                        r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
+                    )
+                } else {
+                    format!(
+                        ".{replacement}()",
+                        replacement = replacement_method_name,
+                    )
+                };
+
+                span_lint_and_sugg(
+                    cx,
+                    UNNECESSARY_FOLD,
+                    fold_span,
+                    // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
+                    "this `.fold` can be written more succinctly using another method",
+                    "try",
+                    sugg,
+                    applicability,
+                );
+            }
+        }
+    }
+
+    // Check that this is a call to Iterator::fold rather than just some function called fold
+    if !match_trait_method(cx, expr, &*paths::ITERATOR) {
+        return;
+    }
+
+    assert!(
+        fold_args.len() == 3,
+        "Expected fold_args to have three entries - the receiver, the initial value and the closure"
+    );
+
+    // Check if the first argument to .fold is a suitable literal
+    match fold_args[1].node {
+        hir::ExprKind::Lit(ref lit) => match lit.node {
+            ast::LitKind::Bool(false) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Or, "any", true),
+            ast::LitKind::Bool(true) => check_fold_with_op(cx, fold_args, hir::BinOpKind::And, "all", true),
+            ast::LitKind::Int(0, _) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Add, "sum", false),
+            ast::LitKind::Int(1, _) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Mul, "product", false),
+            _ => return,
+        },
+        _ => return,
+    };
+}
+
+fn lint_iter_nth<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, iter_args: &'tcx [hir::Expr], is_mut: bool) {
+    let mut_str = if is_mut { "_mut" } else { "" };
+    let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
+        "slice"
+    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &*paths::VEC) {
+        "Vec"
+    } else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &*paths::VEC_DEQUE) {
+        "VecDeque"
+    } else {
+        return; // caller is not a type that we want to lint
+    };
+
+    span_lint(
+        cx,
+        ITER_NTH,
+        expr.span,
+        &format!(
+            "called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
+            mut_str, caller_type
+        ),
+    );
+}
+
+fn lint_get_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr, get_args: &'tcx [hir::Expr], is_mut: bool) {
+    // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap,
+    // because they do not implement `IndexMut`
+    let mut applicability = Applicability::MachineApplicable;
+    let expr_ty = cx.tables.expr_ty(&get_args[0]);
+    let get_args_str = if get_args.len() > 1 {
+        snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
+    } else {
+        return; // not linting on a .get().unwrap() chain or variant
+    };
+    let mut needs_ref;
+    let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
+        needs_ref = get_args_str.parse::<usize>().is_ok();
+        "slice"
+    } else if match_type(cx, expr_ty, &*paths::VEC) {
+        needs_ref = get_args_str.parse::<usize>().is_ok();
+        "Vec"
+    } else if match_type(cx, expr_ty, &*paths::VEC_DEQUE) {
+        needs_ref = get_args_str.parse::<usize>().is_ok();
+        "VecDeque"
+    } else if !is_mut && match_type(cx, expr_ty, &*paths::HASHMAP) {
+        needs_ref = true;
+        "HashMap"
+    } else if !is_mut && match_type(cx, expr_ty, &*paths::BTREEMAP) {
+        needs_ref = true;
+        "BTreeMap"
+    } else {
+        return; // caller is not a type that we want to lint
+    };
+
+    let mut span = expr.span;
+
+    // Handle the case where the result is immediately dereferenced
+    // by not requiring ref and pulling the dereference into the
+    // suggestion.
+    if_chain! {
+        if needs_ref;
+        if let Some(parent) = get_parent_expr(cx, expr);
+        if let hir::ExprKind::Unary(hir::UnOp::UnDeref, _) = parent.node;
+        then {
+            needs_ref = false;
+            span = parent.span;
+        }
+    }
+
+    let mut_str = if is_mut { "_mut" } else { "" };
+    let borrow_str = if !needs_ref {
+        ""
+    } else if is_mut {
+        "&mut "
+    } else {
+        "&"
+    };
+
+    span_lint_and_sugg(
+        cx,
+        GET_UNWRAP,
+        span,
+        &format!(
+            "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
+            mut_str, caller_type
+        ),
+        "try this",
+        format!(
+            "{}{}[{}]",
+            borrow_str,
+            snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability),
+            get_args_str
+        ),
+        applicability,
+    );
+}
+
+fn lint_iter_skip_next(cx: &LateContext<'_, '_>, expr: &hir::Expr) {
+    // lint if caller of skip is an Iterator
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        span_lint(
+            cx,
+            ITER_SKIP_NEXT,
+            expr.span,
+            "called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`",
+        );
+    }
+}
+
+fn derefs_to_slice<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    ty: Ty<'tcx>,
+) -> Option<&'tcx hir::Expr> {
+    fn may_slice(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
+        match ty.sty {
+            ty::Slice(_) => true,
+            ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
+            ty::Adt(..) => match_type(cx, ty, &*paths::VEC),
+            ty::Array(_, size) => size.assert_usize(cx.tcx).expect("array length") < 32,
+            ty::Ref(_, inner, _) => may_slice(cx, inner),
+            _ => false,
+        }
+    }
+
+    if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.node {
+        if path.ident.name == *sym::iter && may_slice(cx, cx.tables.expr_ty(&args[0])) {
+            Some(&args[0])
+        } else {
+            None
+        }
+    } else {
+        match ty.sty {
+            ty::Slice(_) => Some(expr),
+            ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
+            ty::Ref(_, inner, _) => {
+                if may_slice(cx, inner) {
+                    Some(expr)
+                } else {
+                    None
+                }
+            },
+            _ => None,
+        }
+    }
+}
+
+/// lint use of `unwrap()` for `Option`s and `Result`s
+fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::Expr]) {
+    let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
+
+    let mess = if match_type(cx, obj_ty, &*paths::OPTION) {
+        Some((OPTION_UNWRAP_USED, "an Option", "None"))
+    } else if match_type(cx, obj_ty, &*paths::RESULT) {
+        Some((RESULT_UNWRAP_USED, "a Result", "Err"))
+    } else {
+        None
+    };
+
+    if let Some((lint, kind, none_value)) = mess {
+        span_lint(
+            cx,
+            lint,
+            expr.span,
+            &format!(
+                "used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \
+                 using expect() to provide a better panic \
+                 message",
+                kind, none_value
+            ),
+        );
+    }
+}
+
+/// lint use of `ok().expect()` for `Result`s
+fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr, ok_args: &[hir::Expr]) {
+    // lint if the caller of `ok()` is a `Result`
+    if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &*paths::RESULT) {
+        let result_type = cx.tables.expr_ty(&ok_args[0]);
+        if let Some(error_type) = get_error_type(cx, result_type) {
+            if has_debug_impl(error_type, cx) {
+                span_lint(
+                    cx,
+                    OK_EXPECT,
+                    expr.span,
+                    "called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`",
+                );
+            }
+        }
+    }
+}
+
+/// lint use of `map().flatten()` for `Iterators`
+fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr]) {
+    // lint if caller of `.map().flatten()` is an Iterator
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `map(..).flatten()` on an `Iterator`. \
+                   This is more succinctly expressed by calling `.flat_map(..)`";
+        let self_snippet = snippet(cx, map_args[0].span, "..");
+        let func_snippet = snippet(cx, map_args[1].span, "..");
+        let hint = format!("{0}.flat_map({1})", self_snippet, func_snippet);
+        span_lint_and_then(cx, MAP_FLATTEN, expr.span, msg, |db| {
+            db.span_suggestion(
+                expr.span,
+                "try using flat_map instead",
+                hint,
+                Applicability::MachineApplicable,
+            );
+        });
+    }
+}
+
+/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
+fn lint_map_unwrap_or_else<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    map_args: &'tcx [hir::Expr],
+    unwrap_args: &'tcx [hir::Expr],
+) {
+    // lint if the caller of `map()` is an `Option`
+    let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &*paths::OPTION);
+    let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &*paths::RESULT);
+    if is_option || is_result {
+        // lint message
+        let msg = if is_option {
+            "called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling \
+             `map_or_else(g, f)` instead"
+        } else {
+            "called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling \
+             `ok().map_or_else(g, f)` instead"
+        };
+        // get snippets for args to map() and unwrap_or_else()
+        let map_snippet = snippet(cx, map_args[1].span, "..");
+        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
+        // lint, with note if neither arg is > 1 line and both map() and
+        // unwrap_or_else() have the same span
+        let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
+        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
+        if same_span && !multiline {
+            span_note_and_lint(
+                cx,
+                if is_option {
+                    OPTION_MAP_UNWRAP_OR_ELSE
+                } else {
+                    RESULT_MAP_UNWRAP_OR_ELSE
+                },
+                expr.span,
+                msg,
+                expr.span,
+                &format!(
+                    "replace `map({0}).unwrap_or_else({1})` with `{2}map_or_else({1}, {0})`",
+                    map_snippet,
+                    unwrap_snippet,
+                    if is_result { "ok()." } else { "" }
+                ),
+            );
+        } else if same_span && multiline {
+            span_lint(
+                cx,
+                if is_option {
+                    OPTION_MAP_UNWRAP_OR_ELSE
+                } else {
+                    RESULT_MAP_UNWRAP_OR_ELSE
+                },
+                expr.span,
+                msg,
+            );
+        };
+    }
+}
+
+/// lint use of `_.map_or(None, _)` for `Option`s
+fn lint_map_or_none<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_or_args: &'tcx [hir::Expr]) {
+    if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &*paths::OPTION) {
+        // check if the first non-self argument to map_or() is None
+        let map_or_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].node {
+            match_qpath(qpath, &*paths::OPTION_NONE)
+        } else {
+            false
+        };
+
+        if map_or_arg_is_none {
+            // lint message
+            let msg = "called `map_or(None, f)` on an Option value. This can be done more directly by calling \
+                       `and_then(f)` instead";
+            let map_or_self_snippet = snippet(cx, map_or_args[0].span, "..");
+            let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
+            let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
+            span_lint_and_then(cx, OPTION_MAP_OR_NONE, expr.span, msg, |db| {
+                db.span_suggestion(
+                    expr.span,
+                    "try using and_then instead",
+                    hint,
+                    Applicability::MachineApplicable, // snippet
+                );
+            });
+        }
+    }
+}
+
+/// 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
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
+                   `.find(p)` instead.";
+        let filter_snippet = snippet(cx, filter_args[1].span, "..");
+        if filter_snippet.lines().count() <= 1 {
+            // add note if not multi-line
+            span_note_and_lint(
+                cx,
+                FILTER_NEXT,
+                expr.span,
+                msg,
+                expr.span,
+                &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
+            );
+        } else {
+            span_lint(cx, FILTER_NEXT, expr.span, msg);
+        }
+    }
+}
+
+/// lint use of `filter().map()` for `Iterators`
+fn lint_filter_map<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    _filter_args: &'tcx [hir::Expr],
+    _map_args: &'tcx [hir::Expr],
+) {
+    // lint if caller of `.filter().map()` is an Iterator
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `filter(p).map(q)` on an `Iterator`. \
+                   This is more succinctly expressed by calling `.filter_map(..)` instead.";
+        span_lint(cx, FILTER_MAP, expr.span, msg);
+    }
+}
+
+/// lint use of `filter_map().next()` for `Iterators`
+fn lint_filter_map_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, filter_args: &'tcx [hir::Expr]) {
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \
+                   `.find_map(p)` instead.";
+        let filter_snippet = snippet(cx, filter_args[1].span, "..");
+        if filter_snippet.lines().count() <= 1 {
+            span_note_and_lint(
+                cx,
+                FILTER_MAP_NEXT,
+                expr.span,
+                msg,
+                expr.span,
+                &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet),
+            );
+        } else {
+            span_lint(cx, FILTER_MAP_NEXT, expr.span, msg);
+        }
+    }
+}
+
+/// lint use of `find().map()` for `Iterators`
+fn lint_find_map<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    _find_args: &'tcx [hir::Expr],
+    map_args: &'tcx [hir::Expr],
+) {
+    // lint if caller of `.filter().map()` is an Iterator
+    if match_trait_method(cx, &map_args[0], &*paths::ITERATOR) {
+        let msg = "called `find(p).map(q)` on an `Iterator`. \
+                   This is more succinctly expressed by calling `.find_map(..)` instead.";
+        span_lint(cx, FIND_MAP, expr.span, msg);
+    }
+}
+
+/// lint use of `filter().map()` for `Iterators`
+fn lint_filter_map_map<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    _filter_args: &'tcx [hir::Expr],
+    _map_args: &'tcx [hir::Expr],
+) {
+    // lint if caller of `.filter().map()` is an Iterator
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
+                   This is more succinctly expressed by only calling `.filter_map(..)` instead.";
+        span_lint(cx, FILTER_MAP, expr.span, msg);
+    }
+}
+
+/// lint use of `filter().flat_map()` for `Iterators`
+fn lint_filter_flat_map<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    _filter_args: &'tcx [hir::Expr],
+    _map_args: &'tcx [hir::Expr],
+) {
+    // lint if caller of `.filter().flat_map()` is an Iterator
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `filter(p).flat_map(q)` on an `Iterator`. \
+                   This is more succinctly expressed by calling `.flat_map(..)` \
+                   and filtering by returning an empty Iterator.";
+        span_lint(cx, FILTER_MAP, expr.span, msg);
+    }
+}
+
+/// lint use of `filter_map().flat_map()` for `Iterators`
+fn lint_filter_map_flat_map<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    _filter_args: &'tcx [hir::Expr],
+    _map_args: &'tcx [hir::Expr],
+) {
+    // lint if caller of `.filter_map().flat_map()` is an Iterator
+    if match_trait_method(cx, expr, &*paths::ITERATOR) {
+        let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`. \
+                   This is more succinctly expressed by calling `.flat_map(..)` \
+                   and filtering by returning an empty Iterator.";
+        span_lint(cx, FILTER_MAP, expr.span, msg);
+    }
+}
+
+/// lint searching an Iterator followed by `is_some()`
+fn lint_search_is_some<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx hir::Expr,
+    search_method: &str,
+    search_args: &'tcx [hir::Expr],
+    is_some_args: &'tcx [hir::Expr],
+) {
+    // lint if caller of search is an Iterator
+    if match_trait_method(cx, &is_some_args[0], &*paths::ITERATOR) {
+        let msg = format!(
+            "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
+             expressed by calling `any()`.",
+            search_method
+        );
+        let search_snippet = snippet(cx, search_args[1].span, "..");
+        if search_snippet.lines().count() <= 1 {
+            // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
+            let any_search_snippet = if_chain! {
+                if search_method == "find";
+                if let hir::ExprKind::Closure(_, _, body_id, ..) = search_args[1].node;
+                let closure_body = cx.tcx.hir().body(body_id);
+                if let Some(closure_arg) = closure_body.arguments.get(0);
+                if let hir::PatKind::Ref(..) = closure_arg.pat.node;
+                then {
+                    Some(search_snippet.replacen('&', "", 1))
+                } else {
+                    None
+                }
+            };
+            // add note if not multi-line
+            span_note_and_lint(
+                cx,
+                SEARCH_IS_SOME,
+                expr.span,
+                &msg,
+                expr.span,
+                &format!(
+                    "replace `{0}({1}).is_some()` with `any({2})`",
+                    search_method,
+                    search_snippet,
+                    any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str)
+                ),
+            );
+        } else {
+            span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
+        }
+    }
+}
+
+/// Used for `lint_binary_expr_with_method_call`.
+#[derive(Copy, Clone)]
+struct BinaryExprInfo<'a> {
+    expr: &'a hir::Expr,
+    chain: &'a hir::Expr,
+    other: &'a hir::Expr,
+    eq: bool,
+}
+
+/// Checks for the `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
+fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut BinaryExprInfo<'_>) {
+    macro_rules! lint_with_both_lhs_and_rhs {
+        ($func:ident, $cx:expr, $info:ident) => {
+            if !$func($cx, $info) {
+                ::std::mem::swap(&mut $info.chain, &mut $info.other);
+                if $func($cx, $info) {
+                    return;
+                }
+            }
+        };
+    }
+
+    lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
+    lint_with_both_lhs_and_rhs!(lint_chars_last_cmp, cx, info);
+    lint_with_both_lhs_and_rhs!(lint_chars_next_cmp_with_unwrap, cx, info);
+    lint_with_both_lhs_and_rhs!(lint_chars_last_cmp_with_unwrap, cx, info);
+}
+
+/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_NEXT_CMP` lints.
+fn lint_chars_cmp(
+    cx: &LateContext<'_, '_>,
+    info: &BinaryExprInfo<'_>,
+    chain_methods: &[Symbol],
+    lint: &'static Lint,
+    suggest: &str,
+) -> bool {
+    if_chain! {
+        if let Some(args) = method_chain_args(info.chain, chain_methods);
+        if let hir::ExprKind::Call(ref fun, ref arg_char) = info.other.node;
+        if arg_char.len() == 1;
+        if let hir::ExprKind::Path(ref qpath) = fun.node;
+        if let Some(segment) = single_segment_path(qpath);
+        if segment.ident.name == *sym::Some;
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
+
+            if self_ty.sty != ty::Str {
+                return false;
+            }
+
+            span_lint_and_sugg(
+                cx,
+                lint,
+                info.expr.span,
+                &format!("you should use the `{}` method", suggest),
+                "like this",
+                format!("{}{}.{}({})",
+                        if info.eq { "" } else { "!" },
+                        snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
+                        suggest,
+                        snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)),
+                applicability,
+            );
+
+            return true;
+        }
+    }
+
+    false
+}
+
+/// Checks for the `CHARS_NEXT_CMP` lint.
+fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
+    lint_chars_cmp(cx, info, &[*sym::chars, *sym::next], CHARS_NEXT_CMP, "starts_with")
+}
+
+/// Checks for the `CHARS_LAST_CMP` lint.
+fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
+    if lint_chars_cmp(cx, info, &[*sym::chars, *sym::last], CHARS_LAST_CMP, "ends_with") {
+        true
+    } else {
+        lint_chars_cmp(cx, info, &[*sym::chars, *sym::next_back], CHARS_LAST_CMP, "ends_with")
+    }
+}
+
+/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
+fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    info: &BinaryExprInfo<'_>,
+    chain_methods: &[Symbol],
+    lint: &'static Lint,
+    suggest: &str,
+) -> bool {
+    if_chain! {
+        if let Some(args) = method_chain_args(info.chain, chain_methods);
+        if let hir::ExprKind::Lit(ref lit) = info.other.node;
+        if let ast::LitKind::Char(c) = lit.node;
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                lint,
+                info.expr.span,
+                &format!("you should use the `{}` method", suggest),
+                "like this",
+                format!("{}{}.{}('{}')",
+                        if info.eq { "" } else { "!" },
+                        snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
+                        suggest,
+                        c),
+                applicability,
+            );
+
+            return true;
+        }
+    }
+
+    false
+}
+
+/// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
+fn lint_chars_next_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
+    lint_chars_cmp_with_unwrap(
+        cx,
+        info,
+        &[*sym::chars, *sym::next, *sym::unwrap],
+        CHARS_NEXT_CMP,
+        "starts_with",
+    )
+}
+
+/// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
+fn lint_chars_last_cmp_with_unwrap<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool {
+    if lint_chars_cmp_with_unwrap(
+        cx,
+        info,
+        &[*sym::chars, *sym::last, *sym::unwrap],
+        CHARS_LAST_CMP,
+        "ends_with",
+    ) {
+        true
+    } else {
+        lint_chars_cmp_with_unwrap(
+            cx,
+            info,
+            &[*sym::chars, *sym::next_back, *sym::unwrap],
+            CHARS_LAST_CMP,
+            "ends_with",
+        )
+    }
+}
+
+/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
+fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, _expr: &'tcx hir::Expr, arg: &'tcx hir::Expr) {
+    if_chain! {
+        if let hir::ExprKind::Lit(lit) = &arg.node;
+        if let ast::LitKind::Str(r, _) = lit.node;
+        if r.as_str().len() == 1;
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
+            let c = &snip[1..snip.len() - 1];
+            let hint = format!("'{}'", if c == "'" { "\\'" } else { c });
+            span_lint_and_sugg(
+                cx,
+                SINGLE_CHAR_PATTERN,
+                arg.span,
+                "single-character string constant used as pattern",
+                "try using a char instead",
+                hint,
+                applicability,
+            );
+        }
+    }
+}
+
+/// Checks for the `USELESS_ASREF` lint.
+fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_ref_args: &[hir::Expr]) {
+    // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
+    // check if the call is to the actual `AsRef` or `AsMut` trait
+    if match_trait_method(cx, expr, &*paths::ASREF_TRAIT) || match_trait_method(cx, expr, &*paths::ASMUT_TRAIT) {
+        // check if the type after `as_ref` or `as_mut` is the same as before
+        let recvr = &as_ref_args[0];
+        let rcv_ty = cx.tables.expr_ty(recvr);
+        let res_ty = cx.tables.expr_ty(expr);
+        let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
+        let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
+        if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
+            // allow the `as_ref` or `as_mut` if it is followed by another method call
+            if_chain! {
+                if let Some(parent) = get_parent_expr(cx, expr);
+                if let hir::ExprKind::MethodCall(_, ref span, _) = parent.node;
+                if span != &expr.span;
+                then {
+                    return;
+                }
+            }
+
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                USELESS_ASREF,
+                expr.span,
+                &format!("this call to `{}` does nothing", call_name),
+                "try this",
+                snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(),
+                applicability,
+            );
+        }
+    }
+}
+
+fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: Ty<'_>) -> Option<(&'static Lint, Symbol, &'static str)> {
+    if let Some(ty_name) = has_iter_method(cx, self_ref_ty) {
+        let lint = if ty_name == *sym::array || ty_name == *sym::PathBuf {
+            INTO_ITER_ON_ARRAY
+        } else {
+            INTO_ITER_ON_REF
+        };
+        let mutbl = match self_ref_ty.sty {
+            ty::Ref(_, _, mutbl) => mutbl,
+            _ => unreachable!(),
+        };
+        let method_name = match mutbl {
+            hir::MutImmutable => "iter",
+            hir::MutMutable => "iter_mut",
+        };
+        Some((lint, ty_name, method_name))
+    } else {
+        None
+    }
+}
+
+fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: Ty<'_>, method_span: Span) {
+    if !match_trait_method(cx, expr, &*paths::INTO_ITERATOR) {
+        return;
+    }
+    if let Some((lint, kind, method_name)) = ty_has_iter_method(cx, self_ref_ty) {
+        span_lint_and_sugg(
+            cx,
+            lint,
+            method_span,
+            &format!(
+                "this .into_iter() call is equivalent to .{}() and will not move the {}",
+                method_name, kind,
+            ),
+            "call directly",
+            method_name.to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+/// Given a `Result<T, E>` type, return its error type (`E`).
+fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
+    if let ty::Adt(_, substs) = ty.sty {
+        if match_type(cx, ty, &*paths::RESULT) {
+            substs.types().nth(1)
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
+/// This checks whether a given type is known to implement Debug.
+fn has_debug_impl<'a, 'b>(ty: Ty<'a>, cx: &LateContext<'b, 'a>) -> bool {
+    match cx.tcx.lang_items().debug_trait() {
+        Some(debug) => implements_trait(cx, ty, debug, &[]),
+        None => false,
+    }
+}
+
+enum Convention {
+    Eq(&'static str),
+    StartsWith(&'static str),
+}
+
+#[rustfmt::skip]
+const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
+    (Convention::Eq("new"), &[SelfKind::No]),
+    (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
+    (Convention::StartsWith("from_"), &[SelfKind::No]),
+    (Convention::StartsWith("into_"), &[SelfKind::Value]),
+    (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
+    (Convention::Eq("to_mut"), &[SelfKind::RefMut]),
+    (Convention::StartsWith("to_"), &[SelfKind::Ref]),
+];
+
+#[rustfmt::skip]
+lazy_static! {
+static ref TRAIT_METHODS: [(Symbol, usize, SelfKind, OutType, &'static str); 30] = [
+    (*sym::add, 2, SelfKind::Value, OutType::Any, "std::ops::Add"),
+    (*sym::as_mut, 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
+    (*sym::as_ref, 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
+    (*sym::bitand, 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
+    (*sym::bitor, 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
+    (*sym::bitxor, 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
+    (*sym::borrow, 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
+    (*sym::borrow_mut, 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
+    (*sym::clone, 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
+    (*sym::cmp, 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
+    (*sym::default, 0, SelfKind::No, OutType::Any, "std::default::Default"),
+    (*sym::deref, 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
+    (*sym::deref_mut, 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
+    (*sym::div, 2, SelfKind::Value, OutType::Any, "std::ops::Div"),
+    (*sym::drop, 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
+    (*sym::eq, 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
+    (*sym::from_iter, 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
+    (*sym::from_str, 1, SelfKind::No, OutType::Any, "std::str::FromStr"),
+    (*sym::hash, 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
+    (*sym::index, 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
+    (*sym::index_mut, 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
+    (*sym::into_iter, 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
+    (*sym::mul, 2, SelfKind::Value, OutType::Any, "std::ops::Mul"),
+    (*sym::neg, 1, SelfKind::Value, OutType::Any, "std::ops::Neg"),
+    (*sym::next, 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
+    (*sym::not, 1, SelfKind::Value, OutType::Any, "std::ops::Not"),
+    (*sym::rem, 2, SelfKind::Value, OutType::Any, "std::ops::Rem"),
+    (*sym::shl, 2, SelfKind::Value, OutType::Any, "std::ops::Shl"),
+    (*sym::shr, 2, SelfKind::Value, OutType::Any, "std::ops::Shr"),
+    (*sym::sub, 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
+];
+}
+
+#[rustfmt::skip]
+lazy_static! {
+static ref PATTERN_METHODS: [(Symbol, usize); 17] = [
+    (*sym::contains, 1),
+    (*sym::starts_with, 1),
+    (*sym::ends_with, 1),
+    (*sym::find, 1),
+    (*sym::rfind, 1),
+    (*sym::split, 1),
+    (*sym::rsplit, 1),
+    (*sym::split_terminator, 1),
+    (*sym::rsplit_terminator, 1),
+    (*sym::splitn, 2),
+    (*sym::rsplitn, 2),
+    (*sym::matches, 1),
+    (*sym::rmatches, 1),
+    (*sym::match_indices, 1),
+    (*sym::rmatch_indices, 1),
+    (*sym::trim_start_matches, 1),
+    (*sym::trim_end_matches, 1),
+];
+}
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+enum SelfKind {
+    Value,
+    Ref,
+    RefMut,
+    No,
+}
+
+impl SelfKind {
+    fn matches(
+        self,
+        cx: &LateContext<'_, '_>,
+        ty: &hir::Ty,
+        arg: &hir::Arg,
+        self_ty: &hir::Ty,
+        allow_value_for_ref: bool,
+        generics: &hir::Generics,
+    ) -> bool {
+        // Self types in the HIR are desugared to explicit self types. So it will
+        // always be `self:
+        // SomeType`,
+        // where SomeType can be `Self` or an explicit impl self type (e.g., `Foo` if
+        // the impl is on `Foo`)
+        // Thus, we only need to test equality against the impl self type or if it is
+        // an explicit
+        // `Self`. Furthermore, the only possible types for `self: ` are `&Self`,
+        // `Self`, `&mut Self`,
+        // and `Box<Self>`, including the equivalent types with `Foo`.
+
+        let is_actually_self = |ty| is_self_ty(ty) || SpanlessEq::new(cx).eq_ty(ty, self_ty);
+        if is_self(arg) {
+            match self {
+                SelfKind::Value => is_actually_self(ty),
+                SelfKind::Ref | SelfKind::RefMut => {
+                    if allow_value_for_ref && is_actually_self(ty) {
+                        return true;
+                    }
+                    match ty.node {
+                        hir::TyKind::Rptr(_, ref mt_ty) => {
+                            let mutability_match = if self == SelfKind::Ref {
+                                mt_ty.mutbl == hir::MutImmutable
+                            } else {
+                                mt_ty.mutbl == hir::MutMutable
+                            };
+                            is_actually_self(&mt_ty.ty) && mutability_match
+                        },
+                        _ => false,
+                    }
+                },
+                _ => false,
+            }
+        } else {
+            match self {
+                SelfKind::Value => false,
+                SelfKind::Ref => is_as_ref_or_mut_trait(ty, self_ty, generics, &*paths::ASREF_TRAIT),
+                SelfKind::RefMut => is_as_ref_or_mut_trait(ty, self_ty, generics, &*paths::ASMUT_TRAIT),
+                SelfKind::No => true,
+            }
+        }
+    }
+
+    fn description(self) -> &'static str {
+        match self {
+            SelfKind::Value => "self by value",
+            SelfKind::Ref => "self by reference",
+            SelfKind::RefMut => "self by mutable reference",
+            SelfKind::No => "no self",
+        }
+    }
+}
+
+fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Generics, name: &[Symbol]) -> bool {
+    single_segment_ty(ty).map_or(false, |seg| {
+        generics.params.iter().any(|param| match param.kind {
+            hir::GenericParamKind::Type { .. } => {
+                param.name.ident().name == seg.ident.name
+                    && param.bounds.iter().any(|bound| {
+                        if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
+                            let path = &ptr.trait_ref.path;
+                            match_path(path, name)
+                                && path.segments.last().map_or(false, |s| {
+                                    if let Some(ref params) = s.args {
+                                        if params.parenthesized {
+                                            false
+                                        } else {
+                                            // FIXME(flip1995): messy, improve if there is a better option
+                                            // in the compiler
+                                            let types: Vec<_> = params
+                                                .args
+                                                .iter()
+                                                .filter_map(|arg| match arg {
+                                                    hir::GenericArg::Type(ty) => Some(ty),
+                                                    _ => None,
+                                                })
+                                                .collect();
+                                            types.len() == 1 && (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                        } else {
+                            false
+                        }
+                    })
+            },
+            _ => false,
+        })
+    })
+}
+
+fn is_ty(ty: &hir::Ty, self_ty: &hir::Ty) -> bool {
+    match (&ty.node, &self_ty.node) {
+        (
+            &hir::TyKind::Path(hir::QPath::Resolved(_, ref ty_path)),
+            &hir::TyKind::Path(hir::QPath::Resolved(_, ref self_ty_path)),
+        ) => ty_path
+            .segments
+            .iter()
+            .map(|seg| seg.ident.name)
+            .eq(self_ty_path.segments.iter().map(|seg| seg.ident.name)),
+        _ => false,
+    }
+}
+
+fn single_segment_ty(ty: &hir::Ty) -> Option<&hir::PathSegment> {
+    if let hir::TyKind::Path(ref path) = ty.node {
+        single_segment_path(path)
+    } else {
+        None
+    }
+}
+
+impl Convention {
+    fn check(&self, other: &str) -> bool {
+        match *self {
+            Convention::Eq(this) => this == other,
+            Convention::StartsWith(this) => other.starts_with(this) && this != other,
+        }
+    }
+}
+
+impl fmt::Display for Convention {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        match *self {
+            Convention::Eq(this) => this.fmt(f),
+            Convention::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
+        }
+    }
+}
+
+#[derive(Clone, Copy)]
+enum OutType {
+    Unit,
+    Bool,
+    Any,
+    Ref,
+}
+
+impl OutType {
+    fn matches(self, cx: &LateContext<'_, '_>, ty: &hir::FunctionRetTy) -> bool {
+        let is_unit = |ty: &hir::Ty| SpanlessEq::new(cx).eq_ty_kind(&ty.node, &hir::TyKind::Tup(vec![].into()));
+        match (self, ty) {
+            (OutType::Unit, &hir::DefaultReturn(_)) => true,
+            (OutType::Unit, &hir::Return(ref ty)) if is_unit(ty) => true,
+            (OutType::Bool, &hir::Return(ref ty)) if is_bool(ty) => true,
+            (OutType::Any, &hir::Return(ref ty)) if !is_unit(ty) => true,
+            (OutType::Ref, &hir::Return(ref ty)) => matches!(ty.node, hir::TyKind::Rptr(_, _)),
+            _ => false,
+        }
+    }
+}
+
+fn is_bool(ty: &hir::Ty) -> bool {
+    if let hir::TyKind::Path(ref p) = ty.node {
+        match_qpath(p, &[*sym::bool])
+    } else {
+        false
+    }
+}
diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs
new file mode 100644 (file)
index 0000000..ec95f1e
--- /dev/null
@@ -0,0 +1,122 @@
+use crate::utils::paths;
+use crate::utils::{is_copy, match_type, snippet, span_lint, span_note_and_lint};
+use rustc::hir::intravisit::{walk_path, NestedVisitorMap, Visitor};
+use rustc::hir::{self, *};
+use rustc::lint::LateContext;
+use rustc_data_structures::fx::FxHashSet;
+use syntax::symbol::Symbol;
+
+use super::OPTION_MAP_UNWRAP_OR;
+
+/// lint use of `map().unwrap_or()` for `Option`s
+pub(super) fn lint<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &hir::Expr,
+    map_args: &'tcx [hir::Expr],
+    unwrap_args: &'tcx [hir::Expr],
+) {
+    // lint if the caller of `map()` is an `Option`
+    if match_type(cx, cx.tables.expr_ty(&map_args[0]), &*paths::OPTION) {
+        if !is_copy(cx, cx.tables.expr_ty(&unwrap_args[1])) {
+            // Do not lint if the `map` argument uses identifiers in the `map`
+            // argument that are also used in the `unwrap_or` argument
+
+            let mut unwrap_visitor = UnwrapVisitor {
+                cx,
+                identifiers: FxHashSet::default(),
+            };
+            unwrap_visitor.visit_expr(&unwrap_args[1]);
+
+            let mut map_expr_visitor = MapExprVisitor {
+                cx,
+                identifiers: unwrap_visitor.identifiers,
+                found_identifier: false,
+            };
+            map_expr_visitor.visit_expr(&map_args[1]);
+
+            if map_expr_visitor.found_identifier {
+                return;
+            }
+        }
+
+        // get snippets for args to map() and unwrap_or()
+        let map_snippet = snippet(cx, map_args[1].span, "..");
+        let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
+        // lint message
+        // comparing the snippet from source to raw text ("None") below is safe
+        // because we already have checked the type.
+        let arg = if unwrap_snippet == "None" { "None" } else { "a" };
+        let suggest = if unwrap_snippet == "None" {
+            "and_then(f)"
+        } else {
+            "map_or(a, f)"
+        };
+        let msg = &format!(
+            "called `map(f).unwrap_or({})` on an Option value. \
+             This can be done more directly by calling `{}` instead",
+            arg, suggest
+        );
+        // lint, with note if neither arg is > 1 line and both map() and
+        // unwrap_or() have the same span
+        let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
+        let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
+        if same_span && !multiline {
+            let suggest = if unwrap_snippet == "None" {
+                format!("and_then({})", map_snippet)
+            } else {
+                format!("map_or({}, {})", unwrap_snippet, map_snippet)
+            };
+            let note = format!(
+                "replace `map({}).unwrap_or({})` with `{}`",
+                map_snippet, unwrap_snippet, suggest
+            );
+            span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, &note);
+        } else if same_span && multiline {
+            span_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg);
+        };
+    }
+}
+
+struct UnwrapVisitor<'a, 'tcx: 'a> {
+    cx: &'a LateContext<'a, 'tcx>,
+    identifiers: FxHashSet<Symbol>,
+}
+
+impl<'a, 'tcx: 'a> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
+    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
+        self.identifiers.insert(ident(path));
+        walk_path(self, path);
+    }
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.cx.tcx.hir())
+    }
+}
+
+struct MapExprVisitor<'a, 'tcx: 'a> {
+    cx: &'a LateContext<'a, 'tcx>,
+    identifiers: FxHashSet<Symbol>,
+    found_identifier: bool,
+}
+
+impl<'a, 'tcx: 'a> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> {
+    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
+        if self.identifiers.contains(&ident(path)) {
+            self.found_identifier = true;
+            return;
+        }
+        walk_path(self, path);
+    }
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.cx.tcx.hir())
+    }
+}
+
+fn ident(path: &Path) -> Symbol {
+    path.segments
+        .last()
+        .expect("segments should be composed of at least 1 element")
+        .ident
+        .name
+}
diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs
new file mode 100644 (file)
index 0000000..31bea83
--- /dev/null
@@ -0,0 +1,141 @@
+use crate::utils::paths;
+use crate::utils::usage::mutated_variables;
+use crate::utils::{match_qpath, match_trait_method, span_lint};
+use rustc::hir;
+use rustc::hir::def::Res;
+use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc::lint::LateContext;
+
+use if_chain::if_chain;
+
+use super::UNNECESSARY_FILTER_MAP;
+
+pub(super) fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
+    if !match_trait_method(cx, expr, &*paths::ITERATOR) {
+        return;
+    }
+
+    if let hir::ExprKind::Closure(_, _, body_id, ..) = args[1].node {
+        let body = cx.tcx.hir().body(body_id);
+        let arg_id = body.arguments[0].pat.hir_id;
+        let mutates_arg = match mutated_variables(&body.value, cx) {
+            Some(used_mutably) => used_mutably.contains(&arg_id),
+            None => true,
+        };
+
+        let (mut found_mapping, mut found_filtering) = check_expression(&cx, arg_id, &body.value);
+
+        let mut return_visitor = ReturnVisitor::new(&cx, arg_id);
+        return_visitor.visit_expr(&body.value);
+        found_mapping |= return_visitor.found_mapping;
+        found_filtering |= return_visitor.found_filtering;
+
+        if !found_filtering {
+            span_lint(
+                cx,
+                UNNECESSARY_FILTER_MAP,
+                expr.span,
+                "this `.filter_map` can be written more simply using `.map`",
+            );
+            return;
+        }
+
+        if !found_mapping && !mutates_arg {
+            span_lint(
+                cx,
+                UNNECESSARY_FILTER_MAP,
+                expr.span,
+                "this `.filter_map` can be written more simply using `.filter`",
+            );
+            return;
+        }
+    }
+}
+
+// returns (found_mapping, found_filtering)
+fn check_expression<'a, 'tcx: 'a>(
+    cx: &'a LateContext<'a, 'tcx>,
+    arg_id: hir::HirId,
+    expr: &'tcx hir::Expr,
+) -> (bool, bool) {
+    match &expr.node {
+        hir::ExprKind::Call(ref func, ref args) => {
+            if_chain! {
+                if let hir::ExprKind::Path(ref path) = func.node;
+                then {
+                    if match_qpath(path, &*paths::OPTION_SOME) {
+                        if_chain! {
+                            if let hir::ExprKind::Path(path) = &args[0].node;
+                            if let Res::Local(ref local) = cx.tables.qpath_res(path, args[0].hir_id);
+                            then {
+                                if arg_id == *local {
+                                    return (false, false)
+                                }
+                            }
+                        }
+                        return (true, false);
+                    } else {
+                        // We don't know. It might do anything.
+                        return (true, true);
+                    }
+                }
+            }
+            (true, true)
+        },
+        hir::ExprKind::Block(ref block, _) => {
+            if let Some(expr) = &block.expr {
+                check_expression(cx, arg_id, &expr)
+            } else {
+                (false, false)
+            }
+        },
+        hir::ExprKind::Match(_, ref arms, _) => {
+            let mut found_mapping = false;
+            let mut found_filtering = false;
+            for arm in arms {
+                let (m, f) = check_expression(cx, arg_id, &arm.body);
+                found_mapping |= m;
+                found_filtering |= f;
+            }
+            (found_mapping, found_filtering)
+        },
+        hir::ExprKind::Path(path) if match_qpath(path, &*paths::OPTION_NONE) => (false, true),
+        _ => (true, true),
+    }
+}
+
+struct ReturnVisitor<'a, 'tcx: 'a> {
+    cx: &'a LateContext<'a, 'tcx>,
+    arg_id: hir::HirId,
+    // Found a non-None return that isn't Some(input)
+    found_mapping: bool,
+    // Found a return that isn't Some
+    found_filtering: bool,
+}
+
+impl<'a, 'tcx: 'a> ReturnVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'a, 'tcx>, arg_id: hir::HirId) -> ReturnVisitor<'a, 'tcx> {
+        ReturnVisitor {
+            cx,
+            arg_id,
+            found_mapping: false,
+            found_filtering: false,
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+        if let hir::ExprKind::Ret(Some(expr)) = &expr.node {
+            let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr);
+            self.found_mapping |= found_mapping;
+            self.found_filtering |= found_filtering;
+        } else {
+            walk_expr(self, expr);
+        }
+    }
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+}
index bc573841cc80d0651c6a3ff0c670bb56eba1feeb..5a9634571272ffa0bb54b33153ddb61f50827d95 100644 (file)
@@ -1,38 +1,31 @@
 use crate::consts::{constant_simple, Constant};
-use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
+use crate::utils::{match_def_path, paths, span_lint};
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use std::cmp::Ordering;
 
-/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are
-/// used to clamp values, but switched so that the result is constant.
-///
-/// **Why is this bad?** This is in all probability not the intended outcome. At
-/// the least it hurts readability of the code.
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// min(0, max(100, x))
-/// ```
-/// It will always be equal to `0`. Probably the author meant to clamp the value
-/// between 0 and 100, but has erroneously swapped `min` and `max`.
 declare_clippy_lint! {
+    /// **What it does:** Checks for expressions where `std::cmp::min` and `max` are
+    /// used to clamp values, but switched so that the result is constant.
+    ///
+    /// **Why is this bad?** This is in all probability not the intended outcome. At
+    /// the least it hurts readability of the code.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// min(0, max(100, x))
+    /// ```
+    /// It will always be equal to `0`. Probably the author meant to clamp the value
+    /// between 0 and 100, but has erroneously swapped `min` and `max`.
     pub MIN_MAX,
     correctness,
     "`min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant"
 }
 
-#[allow(missing_copy_implementations)]
-pub struct MinMaxPass;
-
-impl LintPass for MinMaxPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MIN_MAX)
-    }
-}
+declare_lint_pass!(MinMaxPass => [MIN_MAX]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MinMaxPass {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
@@ -43,7 +36,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 }
                 match (
                     outer_max,
-                    Constant::partial_cmp(cx.tcx, &cx.tables.expr_ty(ie).sty, &outer_c, &inner_c),
+                    Constant::partial_cmp(cx.tcx, cx.tables.expr_ty(ie), &outer_c, &inner_c),
                 ) {
                     (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
                     _ => {
@@ -69,10 +62,10 @@ enum MinMax {
 fn min_max<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<(MinMax, Constant, &'a Expr)> {
     if let ExprKind::Call(ref path, ref args) = expr.node {
         if let ExprKind::Path(ref qpath) = path.node {
-            opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)).and_then(|def_id| {
-                if match_def_path(cx.tcx, def_id, &paths::CMP_MIN) {
+            cx.tables.qpath_res(qpath, path.hir_id).opt_def_id().and_then(|def_id| {
+                if match_def_path(cx, def_id, &*paths::CMP_MIN) {
                     fetch_const(cx, args, MinMax::Min)
-                } else if match_def_path(cx.tcx, def_id, &paths::CMP_MAX) {
+                } else if match_def_path(cx, def_id, &*paths::CMP_MAX) {
                     fetch_const(cx, args, MinMax::Max)
                 } else {
                     None
index b01d24a1ad33143b26535c5fe2515844e71f18da..66a5ac6824f78206f1a50247386cd51b4014168b 100644 (file)
-use crate::reexport::*;
+use if_chain::if_chain;
 use matches::matches;
-use rustc::hir::*;
 use rustc::hir::intravisit::FnKind;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use syntax::codemap::{ExpnFormat, Span};
-use crate::utils::{get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal,
-            iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint,
-            span_lint_and_then, walk_ptrs_ty, SpanlessEq};
-use crate::utils::sugg::Sugg;
-use syntax::ast::{LitKind, CRATE_NODE_ID};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::LitKind;
+use syntax::source_map::{ExpnFormat, Span};
+
 use crate::consts::{constant, Constant};
+use crate::utils::sugg::Sugg;
+use crate::utils::sym;
+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,
+    span_lint_hir_and_then, walk_ptrs_ty, SpanlessEq,
+};
 
-/// **What it does:** Checks for function arguments and let bindings denoted as
-/// `ref`.
-///
-/// **Why is this bad?** The `ref` declaration makes the function take an owned
-/// value, but turns the argument into a reference (which means that the value
-/// is destroyed when exiting the function). This adds not much value: either
-/// take a reference type, or take an owned value and create references in the
-/// body.
-///
-/// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
-/// type of `x` is more obvious with the former.
-///
-/// **Known problems:** If the argument is dereferenced within the function,
-/// removing the `ref` will lead to errors. This can be fixed by removing the
-/// dereferences, e.g. changing `*x` to `x` within the function.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(ref x: u8) -> bool { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for function arguments and let bindings denoted as
+    /// `ref`.
+    ///
+    /// **Why is this bad?** The `ref` declaration makes the function take an owned
+    /// value, but turns the argument into a reference (which means that the value
+    /// is destroyed when exiting the function). This adds not much value: either
+    /// take a reference type, or take an owned value and create references in the
+    /// body.
+    ///
+    /// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
+    /// type of `x` is more obvious with the former.
+    ///
+    /// **Known problems:** If the argument is dereferenced within the function,
+    /// removing the `ref` will lead to errors. This can be fixed by removing the
+    /// dereferences, e.g., changing `*x` to `x` within the function.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(ref x: u8) -> bool {
+    ///     true
+    /// }
+    /// ```
     pub TOPLEVEL_REF_ARG,
     style,
     "an entire binding declared as `ref`, in a function argument or a `let` statement"
 }
 
-/// **What it does:** Checks for comparisons to NaN.
-///
-/// **Why is this bad?** NaN does not compare meaningfully to anything – not
-/// even itself – so those comparisons are simply wrong.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x == NAN
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for comparisons to NaN.
+    ///
+    /// **Why is this bad?** NaN does not compare meaningfully to anything – not
+    /// even itself – so those comparisons are simply wrong.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use core::f32::NAN;
+    /// # let x = 1.0;
+    ///
+    /// if x == NAN { }
+    /// ```
     pub CMP_NAN,
     correctness,
     "comparisons to NAN, which will always return false, probably not intended"
 }
 
-/// **What it does:** Checks for (in-)equality comparisons on floating-point
-/// values (apart from zero), except in functions called `*eq*` (which probably
-/// implement equality for a type involving floats).
-///
-/// **Why is this bad?** Floating point calculations are usually imprecise, so
-/// asking if two values are *exactly* equal is asking for trouble. For a good
-/// guide on what to do, see [the floating point
-/// guide](http://www.floating-point-gui.de/errors/comparison).
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// y == 1.23f64
-/// y != x  // where both are floats
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for (in-)equality comparisons on floating-point
+    /// values (apart from zero), except in functions called `*eq*` (which probably
+    /// implement equality for a type involving floats).
+    ///
+    /// **Why is this bad?** Floating point calculations are usually imprecise, so
+    /// asking if two values are *exactly* equal is asking for trouble. For a good
+    /// guide on what to do, see [the floating point
+    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = 1.2331f64;
+    /// let y = 1.2332f64;
+    /// if y == 1.23f64 { }
+    /// if y != x {} // where both are floats
+    /// ```
     pub FLOAT_CMP,
     correctness,
     "using `==` or `!=` on float values instead of comparing difference with an epsilon"
 }
 
-/// **What it does:** Checks for conversions to owned values just for the sake
-/// of a comparison.
-///
-/// **Why is this bad?** The comparison can operate on a reference, so creating
-/// an owned value effectively throws it away directly afterwards, which is
-/// needlessly consuming code and heap space.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x.to_owned() == y
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for conversions to owned values just for the sake
+    /// of a comparison.
+    ///
+    /// **Why is this bad?** The comparison can operate on a reference, so creating
+    /// an owned value effectively throws it away directly afterwards, which is
+    /// needlessly consuming code and heap space.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.to_owned() == y
+    /// ```
     pub CMP_OWNED,
     perf,
-    "creating owned instances for comparing with others, e.g. `x == \"foo\".to_string()`"
+    "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`"
 }
 
-/// **What it does:** Checks for getting the remainder of a division by one.
-///
-/// **Why is this bad?** The result can only ever be zero. No one will write
-/// such code deliberately, unless trying to win an Underhanded Rust
-/// Contest. Even for that contest, it's probably a bad idea. Use something more
-/// underhanded.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x % 1
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for getting the remainder of a division by one.
+    ///
+    /// **Why is this bad?** The result can only ever be zero. No one will write
+    /// such code deliberately, unless trying to win an Underhanded Rust
+    /// Contest. Even for that contest, it's probably a bad idea. Use something more
+    /// underhanded.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let x = 1;
+    /// let a = x % 1;
+    /// ```
     pub MODULO_ONE,
     correctness,
     "taking a number modulo 1, which always returns 0"
 }
 
-/// **What it does:** Checks for patterns in the form `name @ _`.
-///
-/// **Why is this bad?** It's almost always more readable to just use direct
-/// bindings.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// match v {
-///     Some(x) => (),
-///     y @ _   => (), // easier written as `y`,
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for patterns in the form `name @ _`.
+    ///
+    /// **Why is this bad?** It's almost always more readable to just use direct
+    /// bindings.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let v = Some("abc");
+    ///
+    /// match v {
+    ///     Some(x) => (),
+    ///     y @ _ => (), // easier written as `y`,
+    /// }
+    /// ```
     pub REDUNDANT_PATTERN,
     style,
     "using `name @ _` in a pattern"
 }
 
-/// **What it does:** Checks for the use of bindings with a single leading
-/// underscore.
-///
-/// **Why is this bad?** A single leading underscore is usually used to indicate
-/// that a binding will not be used. Using such a binding breaks this
-/// expectation.
-///
-/// **Known problems:** The lint does not work properly with desugaring and
-/// macro, it has been allowed in the mean time.
-///
-/// **Example:**
-/// ```rust
-/// let _x = 0;
-/// let y = _x + 1; // Here we are using `_x`, even though it has a leading
-///                 // underscore. We should rename `_x` to `x`
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for the use of bindings with a single leading
+    /// underscore.
+    ///
+    /// **Why is this bad?** A single leading underscore is usually used to indicate
+    /// that a binding will not be used. Using such a binding breaks this
+    /// expectation.
+    ///
+    /// **Known problems:** The lint does not work properly with desugaring and
+    /// macro, it has been allowed in the mean time.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _x = 0;
+    /// let y = _x + 1; // Here we are using `_x`, even though it has a leading
+    ///                 // underscore. We should rename `_x` to `x`
+    /// ```
     pub USED_UNDERSCORE_BINDING,
     pedantic,
     "using a binding which is prefixed with an underscore"
 }
 
-/// **What it does:** Checks for the use of short circuit boolean conditions as
-/// a
-/// statement.
-///
-/// **Why is this bad?** Using a short circuit boolean condition as a statement
-/// may hide the fact that the second part is executed or not depending on the
-/// outcome of the first part.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// f() && g();  // We should write `if f() { g(); }`.
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for the use of short circuit boolean conditions as
+    /// a
+    /// statement.
+    ///
+    /// **Why is this bad?** Using a short circuit boolean condition as a statement
+    /// may hide the fact that the second part is executed or not depending on the
+    /// outcome of the first part.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// f() && g(); // We should write `if f() { g(); }`.
+    /// ```
     pub SHORT_CIRCUIT_STATEMENT,
     complexity,
     "using a short circuit boolean condition as a statement"
 }
 
-/// **What it does:** Catch casts from `0` to some pointer type
-///
-/// **Why is this bad?** This generally means `null` and is better expressed as
-/// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 0 as *const u32
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Catch casts from `0` to some pointer type
+    ///
+    /// **Why is this bad?** This generally means `null` and is better expressed as
+    /// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let a = 0 as *const u32;
+    /// ```
     pub ZERO_PTR,
     style,
     "using 0 as *{const, mut} T"
 }
 
-/// **What it does:** Checks for (in-)equality comparisons on floating-point
-/// value and constant, except in functions called `*eq*` (which probably
-/// implement equality for a type involving floats).
-///
-/// **Why is this bad?** Floating point calculations are usually imprecise, so
-/// asking if two values are *exactly* equal is asking for trouble. For a good
-/// guide on what to do, see [the floating point
-/// guide](http://www.floating-point-gui.de/errors/comparison).
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// const ONE == 1.00f64
-/// x == ONE  // where both are floats
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for (in-)equality comparisons on floating-point
+    /// value and constant, except in functions called `*eq*` (which probably
+    /// implement equality for a type involving floats).
+    ///
+    /// **Why is this bad?** Floating point calculations are usually imprecise, so
+    /// asking if two values are *exactly* equal is asking for trouble. For a good
+    /// guide on what to do, see [the floating point
+    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// const ONE = 1.00f64;
+    /// x == ONE  // where both are floats
+    /// ```
     pub FLOAT_CMP_CONST,
     restriction,
     "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            TOPLEVEL_REF_ARG,
-            CMP_NAN,
-            FLOAT_CMP,
-            CMP_OWNED,
-            MODULO_ONE,
-            REDUNDANT_PATTERN,
-            USED_UNDERSCORE_BINDING,
-            SHORT_CIRCUIT_STATEMENT,
-            ZERO_PTR,
-            FLOAT_CMP_CONST
-        )
-    }
-}
+declare_lint_pass!(MiscLints => [
+    TOPLEVEL_REF_ARG,
+    CMP_NAN,
+    FLOAT_CMP,
+    CMP_OWNED,
+    MODULO_ONE,
+    REDUNDANT_PATTERN,
+    USED_UNDERSCORE_BINDING,
+    SHORT_CIRCUIT_STATEMENT,
+    ZERO_PTR,
+    FLOAT_CMP_CONST
+]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -247,7 +254,7 @@ fn check_fn(
         decl: &'tcx FnDecl,
         body: &'tcx Body,
         _: Span,
-        _: NodeId,
+        _: HirId,
     ) {
         if let FnKind::Closure(_) = k {
             // Does not apply to closures
@@ -255,8 +262,7 @@ fn check_fn(
         }
         for arg in iter_input_pats(decl, body) {
             match arg.pat.node {
-                PatKind::Binding(BindingAnnotation::Ref, _, _, _) |
-                PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => {
+                PatKind::Binding(BindingAnnotation::Ref, ..) | PatKind::Binding(BindingAnnotation::RefMut, ..) => {
                     span_lint(
                         cx,
                         TOPLEVEL_REF_ARG,
@@ -272,41 +278,46 @@ fn check_fn(
 
     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx Stmt) {
         if_chain! {
-            if let StmtKind::Decl(ref d, _) = s.node;
-            if let DeclKind::Local(ref l) = d.node;
-            if let PatKind::Binding(an, _, i, None) = l.pat.node;
+            if let StmtKind::Local(ref l) = s.node;
+            if let PatKind::Binding(an, .., i, None) = l.pat.node;
             if let Some(ref init) = l.init;
             then {
                 if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut {
-                    let init = Sugg::hir(cx, init, "..");
+                    let sugg_init = Sugg::hir(cx, init, "..");
                     let (mutopt,initref) = if an == BindingAnnotation::RefMut {
-                        ("mut ", init.mut_addr())
+                        ("mut ", sugg_init.mut_addr())
                     } else {
-                        ("", init.addr())
+                        ("", sugg_init.addr())
                     };
                     let tyopt = if let Some(ref ty) = l.ty {
                         format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "_"))
                     } else {
-                        "".to_owned()
+                        String::new()
                     };
-                    span_lint_and_then(cx,
+                    span_lint_hir_and_then(cx,
                         TOPLEVEL_REF_ARG,
+                        init.hir_id,
                         l.pat.span,
                         "`ref` on an entire `let` pattern is discouraged, take a reference with `&` instead",
                         |db| {
-                            db.span_suggestion(s.span,
-                                               "try",
-                                               format!("let {name}{tyopt} = {initref};",
-                                                       name=snippet(cx, i.span, "_"),
-                                                       tyopt=tyopt,
-                                                       initref=initref));
+                            db.span_suggestion(
+                                s.span,
+                                "try",
+                                format!(
+                                    "let {name}{tyopt} = {initref};",
+                                    name=snippet(cx, i.span, "_"),
+                                    tyopt=tyopt,
+                                    initref=initref,
+                                ),
+                                Applicability::MachineApplicable, // snippet
+                            );
                         }
                     );
                 }
             }
         };
         if_chain! {
-            if let StmtKind::Semi(ref expr, _) = s.node;
+            if let StmtKind::Semi(ref expr) = s.node;
             if let ExprKind::Binary(ref binop, ref a, ref b) = expr.node;
             if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
             if let Some(sugg) = Sugg::hir_opt(cx, a);
@@ -317,8 +328,16 @@ fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, s: &'tcx Stmt) {
                     "boolean short circuit operator in statement may be clearer using an explicit test",
                     |db| {
                         let sugg = if binop.node == BinOpKind::Or { !sugg } else { sugg };
-                        db.span_suggestion(s.span, "replace it with",
-                                           format!("if {} {{ {}; }}", sugg, &snippet(cx, b.span, "..")));
+                        db.span_suggestion(
+                            s.span,
+                            "replace it with",
+                            format!(
+                                "if {} {{ {}; }}",
+                                sugg,
+                                &snippet(cx, b.span, ".."),
+                            ),
+                            Applicability::MachineApplicable, // snippet
+                        );
                     });
             }
         };
@@ -348,7 +367,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     }
                     if let Some(name) = get_item_name(cx, expr) {
                         let name = name.as_str();
-                        if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_")
+                        if name == "eq"
+                            || name == "ne"
+                            || name == "is_nan"
+                            || name.starts_with("eq_")
                             || name.ends_with("_eq")
                         {
                             return;
@@ -367,6 +389,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                             expr.span,
                             "consider comparing them within some error",
                             format!("({}).abs() < error", lhs - rhs),
+                            Applicability::MachineApplicable, // snippet
                         );
                         db.span_note(expr.span, "std::f32::EPSILON and std::f64::EPSILON are available.");
                     });
@@ -388,7 +411,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     binding != "_result" && // FIXME: #944
                     is_used(cx, expr) &&
                     // don't lint if the declaration is in a macro
-                    non_macro_local(cx, &cx.tables.qpath_def(qpath, expr.hir_id))
+                    non_macro_local(cx, cx.tables.qpath_res(qpath, expr.hir_id))
                 {
                     Some(binding)
                 } else {
@@ -420,13 +443,16 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 
     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
-        if let PatKind::Binding(_, _, ident, Some(ref right)) = pat.node {
+        if let PatKind::Binding(.., ident, Some(ref right)) = pat.node {
             if let PatKind::Wild = right.node {
                 span_lint(
                     cx,
                     REDUNDANT_PATTERN,
                     pat.span,
-                    &format!("the `{} @ _` pattern can be written as just `{}`", ident.name, ident.name),
+                    &format!(
+                        "the `{} @ _` pattern can be written as just `{}`",
+                        ident.name, ident.name
+                    ),
                 );
             }
         }
@@ -434,15 +460,15 @@ fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
 }
 
 fn check_nan(cx: &LateContext<'_, '_>, path: &Path, expr: &Expr) {
-    if !in_constant(cx, expr.id) {
+    if !in_constant(cx, expr.hir_id) {
         if let Some(seg) = path.segments.last() {
-            if seg.ident.name == "NAN" {
+            if seg.ident.name == *sym::NAN {
                 span_lint(
                     cx,
                     CMP_NAN,
                     expr.span,
                     "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead",
-                    );
+                );
             }
         }
     }
@@ -452,7 +478,7 @@ fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) ->
     if let Some((_, res)) = constant(cx, cx.tables, expr) {
         res
     } else {
-       false
+        false
     }
 }
 
@@ -465,26 +491,29 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
 }
 
 fn is_float(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
-    matches!(walk_ptrs_ty(cx.tables.expr_ty(expr)).sty, ty::TyFloat(_))
+    matches!(walk_ptrs_ty(cx.tables.expr_ty(expr)).sty, ty::Float(_))
 }
 
 fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
     let (arg_ty, snip) = match expr.node {
         ExprKind::MethodCall(.., ref args) if args.len() == 1 => {
-            if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
+            if match_trait_method(cx, expr, &*paths::TO_STRING) || match_trait_method(cx, expr, &*paths::TO_OWNED) {
                 (cx.tables.expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
             } else {
                 return;
             }
         },
-        ExprKind::Call(ref path, ref v) if v.len() == 1 => if let ExprKind::Path(ref path) = path.node {
-            if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
-                (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
+        ExprKind::Call(ref path, ref v) if v.len() == 1 => {
+            if let ExprKind::Path(ref path) = path.node {
+                if match_qpath(path, &[*sym::String, *sym::from_str]) || match_qpath(path, &[*sym::String, *sym::from])
+                {
+                    (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
+                } else {
+                    return;
+                }
             } else {
                 return;
             }
-        } else {
-            return;
         },
         _ => return,
     };
@@ -495,46 +524,55 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
         None => return,
     };
 
-    // *arg impls PartialEq<other>
-    if !arg_ty
-        .builtin_deref(true)
-        .map_or(false, |tam| implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()]))
-        // arg impls PartialEq<*other>
-        && !other_ty
-        .builtin_deref(true)
-        .map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()]))
-        // arg impls PartialEq<other>
-        && !implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()])
-    {
+    let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
+        implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
+    });
+    let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
+        implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
+    });
+    let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
+
+    if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
         return;
     }
 
+    let other_gets_derefed = match other.node {
+        ExprKind::Unary(UnDeref, _) => true,
+        _ => false,
+    };
+
+    let lint_span = if other_gets_derefed {
+        expr.span.to(other.span)
+    } else {
+        expr.span
+    };
+
     span_lint_and_then(
         cx,
         CMP_OWNED,
-        expr.span,
+        lint_span,
         "this creates an owned instance just for comparison",
         |db| {
-            // this is as good as our recursion check can get, we can't prove that the
-            // current function is
-            // called by
-            // PartialEq::eq, but we can at least ensure that this code is not part of it
-            let parent_fn = cx.tcx.hir.get_parent(expr.id);
-            let parent_impl = cx.tcx.hir.get_parent(parent_fn);
-            if parent_impl != CRATE_NODE_ID {
-                if let map::NodeItem(item) = cx.tcx.hir.get(parent_impl) {
-                    if let ItemKind::Impl(.., Some(ref trait_ref), _, _) = item.node {
-                        if trait_ref.path.def.def_id() == partial_eq_trait_id {
-                            // we are implementing PartialEq, don't suggest not doing `to_owned`, otherwise
-                            // we go into
-                            // recursion
-                            db.span_label(expr.span, "try calling implementing the comparison without allocating");
-                            return;
-                        }
-                    }
-                }
+            // This also catches `PartialEq` implementations that call `to_owned`.
+            if other_gets_derefed {
+                db.span_label(lint_span, "try implementing the comparison without allocating");
+                return;
             }
-            db.span_suggestion(expr.span, "try", snip.to_string());
+
+            let try_hint = if deref_arg_impl_partial_eq_other {
+                // suggest deref on the left
+                format!("*{}", snip)
+            } else {
+                // suggest dropping the to_owned on the left
+                snip.to_string()
+            };
+
+            db.span_suggestion(
+                lint_span,
+                "try",
+                try_hint,
+                Applicability::MachineApplicable, // snippet
+            );
         },
     );
 }
@@ -553,9 +591,8 @@ fn is_used(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
     }
 }
 
-/// Test whether an expression is in a macro expansion (e.g. something
-/// generated by
-/// `#[derive(...)`] or the like).
+/// Tests whether an expression is in a macro expansion (e.g., something
+/// generated by `#[derive(...)]` or the like).
 fn in_attributes_expansion(expr: &Expr) -> bool {
     expr.span
         .ctxt()
@@ -564,10 +601,10 @@ fn in_attributes_expansion(expr: &Expr) -> bool {
         .map_or(false, |info| matches!(info.format, ExpnFormat::MacroAttribute(_)))
 }
 
-/// Test whether `def` is a variable defined outside a macro.
-fn non_macro_local(cx: &LateContext<'_, '_>, def: &def::Def) -> bool {
-    match *def {
-        def::Def::Local(id) | def::Def::Upvar(id, _, _) => !in_macro(cx.tcx.hir.span(id)),
+/// Tests whether `res` is a variable defined outside a macro.
+fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool {
+    match res {
+        def::Res::Local(id) | def::Res::Upvar(id, ..) => !in_macro_or_desugar(cx.tcx.hir().span_by_hir_id(id)),
         _ => false,
     }
 }
@@ -578,7 +615,7 @@ fn check_cast(cx: &LateContext<'_, '_>, span: Span, e: &Expr, ty: &Ty) {
         if let ExprKind::Lit(ref lit) = e.node;
         if let LitKind::Int(value, ..) = lit.node;
         if value == 0;
-        if !in_constant(cx, e.id);
+        if !in_constant(cx, e.hir_id);
         then {
             let msg = match mutbl {
                 Mutability::MutMutable => "`0 as *mut _` detected. Consider using `ptr::null_mut()`",
index 9b8e0743f39354895428940acabf2673d4ed1e54..c2e42a0a9933cdf66219b23b880c6997d27272c1 100644 (file)
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then};
 use if_chain::if_chain;
-use std::collections::HashMap;
+use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::Applicability;
 use std::char;
 use syntax::ast::*;
-use syntax::codemap::Span;
-use syntax::visit::FnKind;
-use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then};
+use syntax::source_map::Span;
+use syntax::visit::{walk_expr, FnKind, Visitor};
 
-/// **What it does:** Checks for structure field patterns bound to wildcards.
-///
-/// **Why is this bad?** Using `..` instead is shorter and leaves the focus on
-/// the fields that are actually bound.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let { a: _, b: ref b, c: _ } = ..
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for structure field patterns bound to wildcards.
+    ///
+    /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on
+    /// the fields that are actually bound.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let { a: _, b: ref b, c: _ } = ..
+    /// ```
     pub UNNEEDED_FIELD_PATTERN,
     style,
     "struct fields bound to a wildcard instead of using `..`"
 }
 
-/// **What it does:** Checks for function arguments having the similar names
-/// differing by an underscore.
-///
-/// **Why is this bad?** It affects code readability.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(a: i32, _a: i32) {}
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for function arguments having the similar names
+    /// differing by an underscore.
+    ///
+    /// **Why is this bad?** It affects code readability.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(a: i32, _a: i32) {}
+    /// ```
     pub DUPLICATE_UNDERSCORE_ARGUMENT,
     style,
     "function arguments having names which only differ by an underscore"
 }
 
-/// **What it does:** Detects closures called in the same expression where they
-/// are defined.
-///
-/// **Why is this bad?** It is unnecessarily adding to the expression's
-/// complexity.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// (|| 42)()
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects closures called in the same expression where they
+    /// are defined.
+    ///
+    /// **Why is this bad?** It is unnecessarily adding to the expression's
+    /// complexity.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// (|| 42)()
+    /// ```
     pub REDUNDANT_CLOSURE_CALL,
     complexity,
     "throwaway closures called in the expression they are defined"
 }
 
-/// **What it does:** Detects expressions of the form `--x`.
-///
-/// **Why is this bad?** It can mislead C/C++ programmers to think `x` was
-/// decremented.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// --x;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects expressions of the form `--x`.
+    ///
+    /// **Why is this bad?** It can mislead C/C++ programmers to think `x` was
+    /// decremented.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut x = 3;
+    /// --x;
+    /// ```
     pub DOUBLE_NEG,
     style,
     "`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
 }
 
-/// **What it does:** Warns on hexadecimal literals with mixed-case letter
-/// digits.
-///
-/// **Why is this bad?** It looks confusing.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let y = 0x1a9BAcD;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Warns on hexadecimal literals with mixed-case letter
+    /// digits.
+    ///
+    /// **Why is this bad?** It looks confusing.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let y = 0x1a9BAcD;
+    /// ```
     pub MIXED_CASE_HEX_LITERALS,
     style,
     "hex literals whose letter digits are not consistently upper- or lowercased"
 }
 
-/// **What it does:** Warns if literal suffixes are not separated by an
-/// underscore.
-///
-/// **Why is this bad?** It is much less readable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let y = 123832i32;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Warns if literal suffixes are not separated by an
+    /// underscore.
+    ///
+    /// **Why is this bad?** It is much less readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let y = 123832i32;
+    /// ```
     pub UNSEPARATED_LITERAL_SUFFIX,
     pedantic,
     "literals whose suffix is not separated by an underscore"
 }
 
-/// **What it does:** Warns if an integral constant literal starts with `0`.
-///
-/// **Why is this bad?** In some languages (including the infamous C language
-/// and most of its
-/// family), this marks an octal constant. In Rust however, this is a decimal
-/// constant. This could
-/// be confusing for both the writer and a reader of the constant.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// In Rust:
-/// ```rust
-/// fn main() {
-///     let a = 0123;
-///     println!("{}", a);
-/// }
-/// ```
-///
-/// prints `123`, while in C:
-///
-/// ```c
-/// #include <stdio.h>
-///
-/// int main() {
-///     int a = 0123;
-///     printf("%d\n", a);
-/// }
-/// ```
-///
-/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
 declare_clippy_lint! {
+    /// **What it does:** Warns if an integral constant literal starts with `0`.
+    ///
+    /// **Why is this bad?** In some languages (including the infamous C language
+    /// and most of its
+    /// family), this marks an octal constant. In Rust however, this is a decimal
+    /// constant. This could
+    /// be confusing for both the writer and a reader of the constant.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// In Rust:
+    /// ```rust
+    /// fn main() {
+    ///     let a = 0123;
+    ///     println!("{}", a);
+    /// }
+    /// ```
+    ///
+    /// prints `123`, while in C:
+    ///
+    /// ```c
+    /// #include <stdio.h>
+    ///
+    /// int main() {
+    ///     int a = 0123;
+    ///     printf("%d\n", a);
+    /// }
+    /// ```
+    ///
+    /// prints `83` (as `83 == 0o123` while `123 == 0o173`).
     pub ZERO_PREFIXED_LITERAL,
     complexity,
     "integer literals starting with `0`"
 }
 
-/// **What it does:** Warns if a generic shadows a built-in type.
-///
-/// **Why is this bad?** This gives surprising type errors.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// impl<u32> Foo<u32> {
-///     fn impl_func(&self) -> u32 {
-///         42
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Warns if a generic shadows a built-in type.
+    ///
+    /// **Why is this bad?** This gives surprising type errors.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```ignore
+    /// impl<u32> Foo<u32> {
+    ///     fn impl_func(&self) -> u32 {
+    ///         42
+    ///     }
+    /// }
+    /// ```
     pub BUILTIN_TYPE_SHADOW,
     style,
     "shadowing a builtin type"
 }
 
-#[derive(Copy, Clone)]
-pub struct MiscEarly;
+declare_lint_pass!(MiscEarlyLints => [
+    UNNEEDED_FIELD_PATTERN,
+    DUPLICATE_UNDERSCORE_ARGUMENT,
+    REDUNDANT_CLOSURE_CALL,
+    DOUBLE_NEG,
+    MIXED_CASE_HEX_LITERALS,
+    UNSEPARATED_LITERAL_SUFFIX,
+    ZERO_PREFIXED_LITERAL,
+    BUILTIN_TYPE_SHADOW
+]);
+
+// Used to find `return` statements or equivalents e.g., `?`
+struct ReturnVisitor {
+    found_return: bool,
+}
+
+impl ReturnVisitor {
+    fn new() -> Self {
+        Self { found_return: false }
+    }
+}
 
-impl LintPass for MiscEarly {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            UNNEEDED_FIELD_PATTERN,
-            DUPLICATE_UNDERSCORE_ARGUMENT,
-            REDUNDANT_CLOSURE_CALL,
-            DOUBLE_NEG,
-            MIXED_CASE_HEX_LITERALS,
-            UNSEPARATED_LITERAL_SUFFIX,
-            ZERO_PREFIXED_LITERAL,
-            BUILTIN_TYPE_SHADOW
-        )
+impl<'ast> Visitor<'ast> for ReturnVisitor {
+    fn visit_expr(&mut self, ex: &'ast Expr) {
+        if let ExprKind::Ret(_) = ex.node {
+            self.found_return = true;
+        } else if let ExprKind::Try(_) = ex.node {
+            self.found_return = true;
+        }
+
+        walk_expr(self, ex)
     }
 }
 
-impl EarlyLintPass for MiscEarly {
+impl EarlyLintPass for MiscEarlyLints {
     fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
         for param in &gen.params {
             if let GenericParamKind::Type { .. } = param.kind {
@@ -208,7 +226,8 @@ fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
         if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
             let mut wilds = 0;
-            let type_name = npat.segments
+            let type_name = npat
+                .segments
                 .last()
                 .expect("A path must have at least one segment")
                 .ident
@@ -235,8 +254,10 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
                 for field in pfields {
                     match field.node.pat.node {
                         PatKind::Wild => {},
-                        _ => if let Ok(n) = cx.sess().codemap().span_to_snippet(field.span) {
-                            normal.push(n);
+                        _ => {
+                            if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
+                                normal.push(n);
+                            }
                         },
                     }
                 }
@@ -267,7 +288,7 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
     }
 
     fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, decl: &FnDecl, _: Span, _: NodeId) {
-        let mut registered_names: HashMap<String, Span> = HashMap::new();
+        let mut registered_names: FxHashMap<String, Span> = FxHashMap::default();
 
         for arg in &decl.inputs {
             if let PatKind::Ident(_, ident, None) = arg.pat.node {
@@ -298,28 +319,43 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
             return;
         }
         match expr.node {
-            ExprKind::Call(ref paren, _) => if let ExprKind::Paren(ref closure) = paren.node {
-                if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
-                    span_lint_and_then(
+            ExprKind::Call(ref paren, _) => {
+                if let ExprKind::Paren(ref closure) = paren.node {
+                    if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
+                        let mut visitor = ReturnVisitor::new();
+                        visitor.visit_expr(block);
+                        if !visitor.found_return {
+                            span_lint_and_then(
+                                cx,
+                                REDUNDANT_CLOSURE_CALL,
+                                expr.span,
+                                "Try not to call a closure in the expression where it is declared.",
+                                |db| {
+                                    if decl.inputs.is_empty() {
+                                        let hint = snippet(cx, block.span, "..").into_owned();
+                                        db.span_suggestion(
+                                            expr.span,
+                                            "Try doing something like: ",
+                                            hint,
+                                            Applicability::MachineApplicable, // snippet
+                                        );
+                                    }
+                                },
+                            );
+                        }
+                    }
+                }
+            },
+            ExprKind::Unary(UnOp::Neg, ref inner) => {
+                if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
+                    span_lint(
                         cx,
-                        REDUNDANT_CLOSURE_CALL,
+                        DOUBLE_NEG,
                         expr.span,
-                        "Try not to call a closure in the expression where it is declared.",
-                        |db| if decl.inputs.is_empty() {
-                            let hint = snippet(cx, block.span, "..").into_owned();
-                            db.span_suggestion(expr.span, "Try doing something like: ", hint);
-                        },
+                        "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
                     );
                 }
             },
-            ExprKind::Unary(UnOp::Neg, ref inner) => if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
-                span_lint(
-                    cx,
-                    DOUBLE_NEG,
-                    expr.span,
-                    "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
-                );
-            },
             ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
             _ => (),
         }
@@ -351,7 +387,7 @@ fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
     }
 }
 
-impl MiscEarly {
+impl MiscEarlyLints {
     fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
         if_chain! {
             if let LitKind::Int(value, ..) = lit.node;
@@ -395,12 +431,14 @@ fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
                         db.span_suggestion(
                             lit.span,
                             "if you mean to use a decimal constant, remove the `0` to remove confusion",
-                            src.trim_left_matches(|c| c == '_' || c == '0').to_string(),
+                            src.trim_start_matches(|c| c == '_' || c == '0').to_string(),
+                            Applicability::MaybeIncorrect,
                         );
                         db.span_suggestion(
                             lit.span,
                             "if you mean to use an octal constant, use `0o`",
-                            format!("0o{}", src.trim_left_matches(|c| c == '_' || c == '0')),
+                            format!("0o{}", src.trim_start_matches(|c| c == '_' || c == '0')),
+                            Applicability::MaybeIncorrect,
                         );
                     });
                 }
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
new file mode 100644 (file)
index 0000000..54f34d6
--- /dev/null
@@ -0,0 +1,109 @@
+use crate::utils::{is_entrypoint_fn, span_lint, trait_ref_of_method};
+use rustc::hir;
+use rustc::hir::intravisit::FnKind;
+use rustc::hir::{Body, Constness, FnDecl, HirId};
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn;
+use syntax_pos::Span;
+
+declare_clippy_lint! {
+    /// **What it does:**
+    ///
+    /// Suggests the use of `const` in functions and methods where possible.
+    ///
+    /// **Why is this bad?**
+    ///
+    /// Not having the function const prevents callers of the function from being const as well.
+    ///
+    /// **Known problems:**
+    ///
+    /// Const functions are currently still being worked on, with some features only being available
+    /// on nightly. This lint does not consider all edge cases currently and the suggestions may be
+    /// incorrect if you are using this lint on stable.
+    ///
+    /// Also, the lint only runs one pass over the code. Consider these two non-const functions:
+    ///
+    /// ```rust
+    /// fn a() -> i32 {
+    ///     0
+    /// }
+    /// fn b() -> i32 {
+    ///     a()
+    /// }
+    /// ```
+    ///
+    /// When running Clippy, the lint will only suggest to make `a` const, because `b` at this time
+    /// can't be const as it calls a non-const function. Making `a` const and running Clippy again,
+    /// will suggest to make `b` const, too.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// fn new() -> Self {
+    ///     Self { random_number: 42 }
+    /// }
+    /// ```
+    ///
+    /// Could be a const fn:
+    ///
+    /// ```rust
+    /// const fn new() -> Self {
+    ///     Self { random_number: 42 }
+    /// }
+    /// ```
+    pub MISSING_CONST_FOR_FN,
+    nursery,
+    "Lint functions definitions that could be made `const fn`"
+}
+
+declare_lint_pass!(MissingConstForFn => [MISSING_CONST_FOR_FN]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingConstForFn {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'_, '_>,
+        kind: FnKind<'_>,
+        _: &FnDecl,
+        _: &Body,
+        span: Span,
+        hir_id: HirId,
+    ) {
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id);
+
+        if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id) {
+            return;
+        }
+
+        // Perform some preliminary checks that rule out constness on the Clippy side. This way we
+        // can skip the actual const check and return early.
+        match kind {
+            FnKind::ItemFn(_, _, header, ..) => {
+                if already_const(header) {
+                    return;
+                }
+            },
+            FnKind::Method(_, sig, ..) => {
+                if trait_ref_of_method(cx, hir_id).is_some() || already_const(sig.header) {
+                    return;
+                }
+            },
+            _ => return,
+        }
+
+        let mir = cx.tcx.optimized_mir(def_id);
+
+        if let Err((span, err)) = is_min_const_fn(cx.tcx, def_id, &mir) {
+            if cx.tcx.is_min_const_fn(def_id) {
+                cx.tcx.sess.span_err(span, &err);
+            }
+        } else {
+            span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a const_fn");
+        }
+    }
+}
+
+// We don't have to lint on something that's already `const`
+fn already_const(header: hir::FnHeader) -> bool {
+    header.constness == Constness::Const
+}
index fe2bbbdb9af0b0308fa1bf5e54815cef1ad7aec2..94c8e7ff709c262febfadd8da563788e08c2264a 100644 (file)
@@ -1,16 +1,3 @@
-// This file incorporates work covered by the following copyright and
-// permission notice:
-//   Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-//   file at the top-level directory of this distribution and at
-//   http://rust-lang.org/COPYRIGHT.
-//
-//   Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-//   http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-//   <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-//   option. This file may not be copied, modified, or distributed
-//   except according to those terms.
-//
-
 // Note: More specifically this lint is largely inspired (aka copied) from
 // *rustc*'s
 // [`missing_doc`].
 // [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246
 //
 
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, span_lint};
+use if_chain::if_chain;
 use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
-use syntax::ast;
+use rustc::{declare_tool_lint, impl_lint_pass};
+use syntax::ast::{self, MetaItem, MetaItemKind};
 use syntax::attr;
-use syntax::codemap::Span;
-use crate::utils::in_macro;
-
-/// **What it does:** Warns if there is missing doc for any documentable item
-/// (public or private).
-///
-/// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS`
-/// allowed-by-default lint for
-/// public members, but has no way to enforce documentation of private items.
-/// This lint fixes that.
-///
-/// **Known problems:** None.
+use syntax::source_map::Span;
+
 declare_clippy_lint! {
+    /// **What it does:** Warns if there is missing doc for any documentable item
+    /// (public or private).
+    ///
+    /// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS`
+    /// allowed-by-default lint for
+    /// public members, but has no way to enforce documentation of private items.
+    /// This lint fixes that.
+    ///
+    /// **Known problems:** None.
     pub MISSING_DOCS_IN_PRIVATE_ITEMS,
     restriction,
     "detects missing documentation for public and private members"
@@ -62,12 +51,30 @@ pub fn new() -> Self {
     }
 
     fn doc_hidden(&self) -> bool {
-        *self.doc_hidden_stack
-            .last()
-            .expect("empty doc_hidden_stack")
+        *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
     }
 
-    fn check_missing_docs_attrs(&self, cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
+    fn has_include(meta: Option<MetaItem>) -> bool {
+        if_chain! {
+            if let Some(meta) = meta;
+            if let MetaItemKind::List(list) = meta.node;
+            if let Some(meta) = list.get(0);
+            if let Some(name) = meta.ident();
+            then {
+                name.as_str() == "include"
+            } else {
+                false
+            }
+        }
+    }
+
+    fn check_missing_docs_attrs(
+        &self,
+        cx: &LateContext<'_, '_>,
+        attrs: &[ast::Attribute],
+        sp: Span,
+        desc: &'static str,
+    ) {
         // If we're building a test harness, then warning about
         // documentation is probably not really relevant right now.
         if cx.sess().opts.test {
@@ -79,15 +86,16 @@ fn check_missing_docs_attrs(&self, cx: &LateContext<'_, '_>, attrs: &[ast::Attri
             return;
         }
 
-        if in_macro(sp) {
+        if in_macro_or_desugar(sp) {
             return;
         }
 
         let has_doc = attrs
             .iter()
-            .any(|a| a.is_value_str() && a.name() == "doc");
+            .any(|a| a.check_name(*sym::doc) && (a.is_value_str() || Self::has_include(a.meta())));
         if !has_doc {
-            cx.span_lint(
+            span_lint(
+                cx,
                 MISSING_DOCS_IN_PRIVATE_ITEMS,
                 sp,
                 &format!("missing documentation for {}", desc),
@@ -96,20 +104,18 @@ fn check_missing_docs_attrs(&self, cx: &LateContext<'_, '_>, attrs: &[ast::Attri
     }
 }
 
-impl LintPass for MissingDoc {
-    fn get_lints(&self) -> LintArray {
-        lint_array![MISSING_DOCS_IN_PRIVATE_ITEMS]
-    }
-}
+impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
     fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) {
-        let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
-            attr.check_name("doc") && match attr.meta_item_list() {
-                None => false,
-                Some(l) => attr::list_contains_name(&l[..], "hidden"),
-            }
-        });
+        let doc_hidden = self.doc_hidden()
+            || attrs.iter().any(|attr| {
+                attr.check_name(*sym::doc)
+                    && match attr.meta_item_list() {
+                        None => false,
+                        Some(l) => attr::list_contains_name(&l[..], *sym::hidden),
+                    }
+            });
         self.doc_hidden_stack.push(doc_hidden);
     }
 
@@ -127,9 +133,9 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) {
             hir::ItemKind::Enum(..) => "an enum",
             hir::ItemKind::Fn(..) => {
                 // ignore main()
-                if it.name == "main" {
-                    let def_id = cx.tcx.hir.local_def_id(it.id);
-                    let def_key = cx.tcx.hir.def_key(def_id);
+                if it.ident.name == *sym::main {
+                    let def_id = cx.tcx.hir().local_def_id_from_hir_id(it.hir_id);
+                    let def_key = cx.tcx.hir().def_key(def_id);
                     if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
                         return;
                     }
@@ -141,14 +147,14 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) {
             hir::ItemKind::Struct(..) => "a struct",
             hir::ItemKind::Trait(..) => "a trait",
             hir::ItemKind::TraitAlias(..) => "a trait alias",
-            hir::ItemKind::GlobalAsm(..) => "an assembly blob",
             hir::ItemKind::Ty(..) => "a type alias",
             hir::ItemKind::Union(..) => "a union",
             hir::ItemKind::Existential(..) => "an existential type",
-            hir::ItemKind::ExternCrate(..) |
-            hir::ItemKind::ForeignMod(..) |
-            hir::ItemKind::Impl(..) |
-            hir::ItemKind::Use(..) => return,
+            hir::ItemKind::ExternCrate(..)
+            | hir::ItemKind::ForeignMod(..)
+            | hir::ItemKind::GlobalAsm(..)
+            | hir::ItemKind::Impl(..)
+            | hir::ItemKind::Use(..) => return,
         };
 
         self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc);
@@ -166,11 +172,13 @@ fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx hir
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) {
         // If the method is an impl for a trait, don't doc.
-        let def_id = cx.tcx.hir.local_def_id(impl_item.id);
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
         match cx.tcx.associated_item(def_id).container {
             ty::TraitContainer(_) => return,
-            ty::ImplContainer(cid) => if cx.tcx.impl_trait_ref(cid).is_some() {
-                return;
+            ty::ImplContainer(cid) => {
+                if cx.tcx.impl_trait_ref(cid).is_some() {
+                    return;
+                }
             },
         }
 
index e19ec4da67ed29cd4352924181c908dc96e41b9c..835e856026f6b3c434bea8f78680059fb2052a46 100644 (file)
@@ -1,80 +1,67 @@
-//   Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-//   file at the top-level directory of this distribution and at
-//   http://rust-lang.org/COPYRIGHT.
-//
-//   Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-//   http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-//   <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-//   option. This file may not be copied, modified, or distributed
-//   except according to those terms.
-//
-
+use crate::utils::span_lint;
+use crate::utils::sym;
 use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast;
-use syntax::codemap::Span;
+use syntax::source_map::Span;
 
-/// **What it does:** it lints if an exported function, method, trait method with default impl,
-/// or trait method impl is not `#[inline]`.
-///
-/// **Why is this bad?** In general, it is not. Functions can be inlined across
-/// crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
-/// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
-/// might intend for most of the methods in their public API to be able to be inlined across
-/// crates even when LTO is disabled. For these types of crates, enabling this lint might make sense.
-/// It allows the crate to require all exported methods to be `#[inline]` by default, and then opt
-/// out for specific methods where this might not make sense.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// pub fn foo() {} // missing #[inline]
-/// fn ok() {} // ok
-/// #[inline] pub fn bar() {} // ok
-/// #[inline(always)] pub fn baz() {} // ok
-///
-/// pub trait Bar {
-///   fn bar(); // ok
-///   fn def_bar() {} // missing #[inline]
-/// }
-///
-/// struct Baz;
-/// impl Baz {
-///    fn priv() {} // ok
-/// }
-///
-/// impl Bar for Baz {
-///   fn bar() {} // ok - Baz is not exported
-/// }
-///
-/// pub struct PubBaz;
-/// impl PubBaz {
-///    fn priv() {} // ok
-///    pub not_ptriv() {} // missing #[inline]
-/// }
-///
-/// impl Bar for PubBaz {
-///    fn bar() {} // missing #[inline]
-///    fn def_bar() {} // missing #[inline]
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** it lints if an exported function, method, trait method with default impl,
+    /// or trait method impl is not `#[inline]`.
+    ///
+    /// **Why is this bad?** In general, it is not. Functions can be inlined across
+    /// crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
+    /// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
+    /// might intend for most of the methods in their public API to be able to be inlined across
+    /// crates even when LTO is disabled. For these types of crates, enabling this lint might make
+    /// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
+    /// then opt out for specific methods where this might not make sense.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// pub fn foo() {} // missing #[inline]
+    /// fn ok() {} // ok
+    /// #[inline] pub fn bar() {} // ok
+    /// #[inline(always)] pub fn baz() {} // ok
+    ///
+    /// pub trait Bar {
+    ///   fn bar(); // ok
+    ///   fn def_bar() {} // missing #[inline]
+    /// }
+    ///
+    /// struct Baz;
+    /// impl Baz {
+    ///    fn priv() {} // ok
+    /// }
+    ///
+    /// impl Bar for Baz {
+    ///   fn bar() {} // ok - Baz is not exported
+    /// }
+    ///
+    /// pub struct PubBaz;
+    /// impl PubBaz {
+    ///    fn priv() {} // ok
+    ///    pub not_ptriv() {} // missing #[inline]
+    /// }
+    ///
+    /// impl Bar for PubBaz {
+    ///    fn bar() {} // missing #[inline]
+    ///    fn def_bar() {} // missing #[inline]
+    /// }
+    /// ```
     pub MISSING_INLINE_IN_PUBLIC_ITEMS,
     restriction,
     "detects missing #[inline] attribute for public callables (functions, trait methods, methods...)"
 }
 
-pub struct MissingInline;
-
-fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
-                              attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
-    let has_inline = attrs
-        .iter()
-        .any(|a| a.name() == "inline" );
+fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
+    let has_inline = attrs.iter().any(|a| a.check_name(*sym::inline));
     if !has_inline {
-        cx.span_lint(
+        span_lint(
+            cx,
             MISSING_INLINE_IN_PUBLIC_ITEMS,
             sp,
             &format!("missing `#[inline]` for {}", desc),
@@ -85,19 +72,13 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
 fn is_executable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>) -> bool {
     use rustc::session::config::CrateType;
 
-    cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| {
-        match t {
-            CrateType::CrateTypeExecutable => true,
-            _ => false,
-        }
+    cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t {
+        CrateType::Executable => true,
+        _ => false,
     })
 }
 
-impl LintPass for MissingInline {
-    fn get_lints(&self) -> LintArray {
-        lint_array![MISSING_INLINE_IN_PUBLIC_ITEMS]
-    }
-}
+declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) {
@@ -105,7 +86,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) {
             return;
         }
 
-        if !cx.access_levels.is_exported(it.id) {
+        if !cx.access_levels.is_exported(it.hir_id) {
             return;
         }
         match it.node {
@@ -113,76 +94,70 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item) {
                 let desc = "a function";
                 check_missing_inline_attrs(cx, &it.attrs, it.span, desc);
             },
-            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics,
-                           ref _bounds, ref trait_items)  => {
+            hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, ref trait_items) => {
                 // note: we need to check if the trait is exported so we can't use
                 // `LateLintPass::check_trait_item` here.
                 for tit in trait_items {
-                    let tit_ = cx.tcx.hir.trait_item(tit.id);
+                    let tit_ = cx.tcx.hir().trait_item(tit.id);
                     match tit_.node {
-                        hir::TraitItemKind::Const(..) |
-                        hir::TraitItemKind::Type(..) => {},
+                        hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
                         hir::TraitItemKind::Method(..) => {
                             if tit.defaultness.has_value() {
                                 // trait method with default body needs inline in case
                                 // an impl is not provided
                                 let desc = "a default trait method";
-                                let item = cx.tcx.hir.expect_trait_item(tit.id.node_id);
-                                check_missing_inline_attrs(cx, &item.attrs,
-                                                                item.span, desc);
+                                let item = cx.tcx.hir().expect_trait_item(tit.id.hir_id);
+                                check_missing_inline_attrs(cx, &item.attrs, item.span, desc);
                             }
                         },
                     }
                 }
-            }
-            hir::ItemKind::Const(..) |
-            hir::ItemKind::Enum(..) |
-            hir::ItemKind::Mod(..) |
-            hir::ItemKind::Static(..) |
-            hir::ItemKind::Struct(..) |
-            hir::ItemKind::TraitAlias(..) |
-            hir::ItemKind::GlobalAsm(..) |
-            hir::ItemKind::Ty(..) |
-            hir::ItemKind::Union(..) |
-            hir::ItemKind::Existential(..) |
-            hir::ItemKind::ExternCrate(..) |
-            hir::ItemKind::ForeignMod(..) |
-            hir::ItemKind::Impl(..) |
-            hir::ItemKind::Use(..) => {},
+            },
+            hir::ItemKind::Const(..)
+            | hir::ItemKind::Enum(..)
+            | hir::ItemKind::Mod(..)
+            | hir::ItemKind::Static(..)
+            | hir::ItemKind::Struct(..)
+            | hir::ItemKind::TraitAlias(..)
+            | hir::ItemKind::GlobalAsm(..)
+            | hir::ItemKind::Ty(..)
+            | hir::ItemKind::Union(..)
+            | hir::ItemKind::Existential(..)
+            | hir::ItemKind::ExternCrate(..)
+            | hir::ItemKind::ForeignMod(..)
+            | hir::ItemKind::Impl(..)
+            hir::ItemKind::Use(..) => {},
         };
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) {
-        use rustc::ty::{TraitContainer, ImplContainer};
+        use rustc::ty::{ImplContainer, TraitContainer};
         if is_executable(cx) {
             return;
         }
 
         // If the item being implemented is not exported, then we don't need #[inline]
-        if !cx.access_levels.is_exported(impl_item.id) {
+        if !cx.access_levels.is_exported(impl_item.hir_id) {
             return;
         }
 
         let desc = match impl_item.node {
             hir::ImplItemKind::Method(..) => "a method",
-            hir::ImplItemKind::Const(..) |
-            hir::ImplItemKind::Type(_) |
-            hir::ImplItemKind::Existential(_) => return,
+            hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) | hir::ImplItemKind::Existential(_) => return,
         };
 
-        let def_id = cx.tcx.hir.local_def_id(impl_item.id);
+        let def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
         let trait_def_id = match cx.tcx.associated_item(def_id).container {
             TraitContainer(cid) => Some(cid),
             ImplContainer(cid) => cx.tcx.impl_trait_ref(cid).map(|t| t.def_id),
         };
 
         if let Some(trait_def_id) = trait_def_id {
-            if let Some(n) = cx.tcx.hir.as_local_node_id(trait_def_id) {
-                if !cx.access_levels.is_exported(n) {
-                    // If a trait is being implemented for an item, and the
-                    // trait is not exported, we don't need #[inline]
-                    return;
-                }
+            if cx.tcx.hir().as_local_node_id(trait_def_id).is_some() && !cx.access_levels.is_exported(impl_item.hir_id)
+            {
+                // If a trait is being implemented for an item, and the
+                // trait is not exported, we don't need #[inline]
+                return;
             }
         }
 
index d424604550661c57cc5fad9400dd44caf01fce07..483d8944ecc65be42e610507893a1a3c814b6d5a 100644 (file)
@@ -1,56 +1,46 @@
 //! lint on multiple versions of a crate being used
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::ast::*;
+use crate::utils::span_lint;
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::{ast::*, source_map::DUMMY_SP};
 
 use cargo_metadata;
 use itertools::Itertools;
 
-/// **What it does:** Checks to see if multiple versions of a crate are being
-/// used.
-///
-/// **Why is this bad?** This bloats the size of targets, and can lead to
-/// confusing error messages when structs or traits are used interchangeably
-/// between different versions of a crate.
-///
-/// **Known problems:** Because this can be caused purely by the dependencies
-/// themselves, it's not always possible to fix this issue.
-///
-/// **Example:**
-/// ```toml
-/// # This will pull in both winapi v0.3.4 and v0.2.8, triggering a warning.
-/// [dependencies]
-/// ctrlc = "3.1.0"
-/// ansi_term = "0.11.0"
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks to see if multiple versions of a crate are being
+    /// used.
+    ///
+    /// **Why is this bad?** This bloats the size of targets, and can lead to
+    /// confusing error messages when structs or traits are used interchangeably
+    /// between different versions of a crate.
+    ///
+    /// **Known problems:** Because this can be caused purely by the dependencies
+    /// themselves, it's not always possible to fix this issue.
+    ///
+    /// **Example:**
+    /// ```toml
+    /// # This will pull in both winapi v0.3.4 and v0.2.8, triggering a warning.
+    /// [dependencies]
+    /// ctrlc = "3.1.0"
+    /// ansi_term = "0.11.0"
+    /// ```
     pub MULTIPLE_CRATE_VERSIONS,
     cargo,
     "multiple versions of the same crate being used"
 }
 
-pub struct Pass;
+declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MULTIPLE_CRATE_VERSIONS)
-    }
-}
-
-impl EarlyLintPass for Pass {
-    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
-        let metadata = match cargo_metadata::metadata_deps(None, true) {
-            Ok(metadata) => metadata,
-            Err(_) => {
-                cx.span_lint(
-                    MULTIPLE_CRATE_VERSIONS,
-                    krate.span,
-                    "could not read cargo metadata"
-                );
+impl EarlyLintPass for MultipleCrateVersions {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
+        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().exec() {
+            metadata
+        } else {
+            span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata");
 
-                return;
-            }
+            return;
         };
 
         let mut packages = metadata.packages;
@@ -62,9 +52,10 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
             if group.len() > 1 {
                 let versions = group.into_iter().map(|p| p.version).join(", ");
 
-                cx.span_lint(
+                span_lint(
+                    cx,
                     MULTIPLE_CRATE_VERSIONS,
-                    krate.span,
+                    DUMMY_SP,
                     &format!("multiple versions for dependency `{}`: {}", name, versions),
                 );
             }
index 0413f1ab603ffa2942fdb820d0b5c94a6cbe0d97..3971346dd1ebe36a6b365c3bdecd062a3a05dfd0 100644 (file)
@@ -1,36 +1,29 @@
+use crate::utils::{higher, span_lint};
 use rustc::hir;
 use rustc::hir::intravisit;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
-use crate::utils::{higher, span_lint};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for instances of `mut mut` references.
-///
-/// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the
-/// source. This is either a copy'n'paste error, or it shows a fundamental
-/// misunderstanding of references.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = &mut &mut y;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for instances of `mut mut` references.
+    ///
+    /// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the
+    /// source. This is either a copy'n'paste error, or it shows a fundamental
+    /// misunderstanding of references.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = &mut &mut y;
+    /// ```
     pub MUT_MUT,
     pedantic,
-    "usage of double-mut refs, e.g. `&mut &mut ...`"
+    "usage of double-mut refs, e.g., `&mut &mut ...`"
 }
 
-#[derive(Copy, Clone)]
-pub struct MutMut;
-
-impl LintPass for MutMut {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MUT_MUT)
-    }
-}
+declare_lint_pass!(MutMut => [MUT_MUT]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut {
     fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
@@ -71,12 +64,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
                     expr.span,
                     "generally you want to avoid `&mut &mut _` if possible",
                 );
-            } else if let ty::TyRef(
-                _,
-                _,
-                hir::MutMutable,
-            ) = self.cx.tables.expr_ty(e).sty
-            {
+            } else if let ty::Ref(_, _, hir::MutMutable) = self.cx.tables.expr_ty(e).sty {
                 span_lint(
                     self.cx,
                     MUT_MUT,
@@ -99,8 +87,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
             if let hir::TyKind::Rptr(
                 _,
                 hir::MutTy {
-                    mutbl: hir::MutMutable,
-                    ..
+                    mutbl: hir::MutMutable, ..
                 },
             ) = pty.node
             {
index de4c54444400b2c606029c65d7f2ef849e8407ba..9f356e7ca792e03960df6a1499107c95d407fff1 100644 (file)
@@ -1,52 +1,45 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::ty::{self, Ty};
-use rustc::ty::subst::Subst;
-use rustc::hir::*;
 use crate::utils::span_lint;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::subst::Subst;
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Detects giving a mutable reference to a function that only
-/// requires an immutable reference.
-///
-/// **Why is this bad?** The immutable reference rules out all other references
-/// to the value. Also the code misleads about the intent of the call site.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// my_vec.push(&mut value)
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects giving a mutable reference to a function that only
+    /// requires an immutable reference.
+    ///
+    /// **Why is this bad?** The immutable reference rules out all other references
+    /// to the value. Also the code misleads about the intent of the call site.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// my_vec.push(&mut value)
+    /// ```
     pub UNNECESSARY_MUT_PASSED,
     style,
-    "an argument passed as a mutable reference although the callee only demands an \
-     immutable reference"
+    "an argument passed as a mutable reference although the callee only demands an immutable reference"
 }
 
-
-#[derive(Copy, Clone)]
-pub struct UnnecessaryMutPassed;
-
-impl LintPass for UnnecessaryMutPassed {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNNECESSARY_MUT_PASSED)
-    }
-}
+declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
         match e.node {
-            ExprKind::Call(ref fn_expr, ref arguments) => if let ExprKind::Path(ref path) = fn_expr.node {
-                check_arguments(
-                    cx,
-                    arguments,
-                    cx.tables.expr_ty(fn_expr),
-                    &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
-                );
+            ExprKind::Call(ref fn_expr, ref arguments) => {
+                if let ExprKind::Path(ref path) = fn_expr.node {
+                    check_arguments(
+                        cx,
+                        arguments,
+                        cx.tables.expr_ty(fn_expr),
+                        &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
+                    );
+                }
             },
             ExprKind::MethodCall(ref path, _, ref arguments) => {
-                let def_id = cx.tables.type_dependent_defs()[e.hir_id].def_id();
+                let def_id = cx.tables.type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.tables.node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                 check_arguments(cx, arguments, method_type, &path.ident.as_str())
@@ -58,25 +51,22 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
 
 fn check_arguments<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arguments: &[Expr], type_definition: Ty<'tcx>, name: &str) {
     match type_definition.sty {
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+        ty::FnDef(..) | ty::FnPtr(_) => {
             let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
             for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
                 match parameter.sty {
-                    ty::TyRef(
-                        _,
-                        _,
-                        MutImmutable,
-                    ) |
-                    ty::TyRawPtr(ty::TypeAndMut {
-                        mutbl: MutImmutable,
-                        ..
-                    }) => if let ExprKind::AddrOf(MutMutable, _) = argument.node {
-                        span_lint(
-                            cx,
-                            UNNECESSARY_MUT_PASSED,
-                            argument.span,
-                            &format!("The function/method `{}` doesn't need a mutable reference", name),
-                        );
+                    ty::Ref(_, _, MutImmutable)
+                    | ty::RawPtr(ty::TypeAndMut {
+                        mutbl: MutImmutable, ..
+                    }) => {
+                        if let ExprKind::AddrOf(MutMutable, _) = argument.node {
+                            span_lint(
+                                cx,
+                                UNNECESSARY_MUT_PASSED,
+                                argument.span,
+                                &format!("The function/method `{}` doesn't need a mutable reference", name),
+                            );
+                        }
                     },
                     _ => (),
                 }
index 50ef9f268f29ab5b36e09a8a5bbe38821f2afccc..380844c44db3131a01aa35cd4a0719229e69e88a 100644 (file)
@@ -2,66 +2,60 @@
 //!
 //! This lint is **warn** by default
 
+use crate::utils::{match_type, paths, span_lint};
+use rustc::hir::Expr;
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
 use rustc::ty::{self, Ty};
-use rustc::hir::Expr;
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast;
-use crate::utils::{match_type, paths, span_lint};
 
-/// **What it does:** Checks for usages of `Mutex<X>` where an atomic will do.
-///
-/// **Why is this bad?** Using a mutex just to make access to a plain bool or
-/// reference sequential is shooting flies with cannons.
-/// `std::atomic::AtomicBool` and `std::atomic::AtomicPtr` are leaner and
-/// faster.
-///
-/// **Known problems:** This lint cannot detect if the mutex is actually used
-/// for waiting before a critical section.
-///
-/// **Example:**
-/// ```rust
-/// let x = Mutex::new(&y);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usages of `Mutex<X>` where an atomic will do.
+    ///
+    /// **Why is this bad?** Using a mutex just to make access to a plain bool or
+    /// reference sequential is shooting flies with cannons.
+    /// `std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
+    /// faster.
+    ///
+    /// **Known problems:** This lint cannot detect if the mutex is actually used
+    /// for waiting before a critical section.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = Mutex::new(&y);
+    /// ```
     pub MUTEX_ATOMIC,
     perf,
     "using a mutex where an atomic value could be used instead"
 }
 
-/// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral
-/// type.
-///
-/// **Why is this bad?** Using a mutex just to make access to a plain integer
-/// sequential is
-/// shooting flies with cannons. `std::atomic::usize` is leaner and faster.
-///
-/// **Known problems:** This lint cannot detect if the mutex is actually used
-/// for waiting before a critical section.
-///
-/// **Example:**
-/// ```rust
-/// let x = Mutex::new(0usize);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usages of `Mutex<X>` where `X` is an integral
+    /// type.
+    ///
+    /// **Why is this bad?** Using a mutex just to make access to a plain integer
+    /// sequential is
+    /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
+    ///
+    /// **Known problems:** This lint cannot detect if the mutex is actually used
+    /// for waiting before a critical section.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = Mutex::new(0usize);
+    /// ```
     pub MUTEX_INTEGER,
     nursery,
     "using a mutex for an integer type"
 }
 
-impl LintPass for MutexAtomic {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER)
-    }
-}
-
-pub struct MutexAtomic;
+declare_lint_pass!(Mutex => [MUTEX_ATOMIC, MUTEX_INTEGER]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutexAtomic {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Mutex {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         let ty = cx.tables.expr_ty(expr);
-        if let ty::TyAdt(_, subst) = ty.sty {
-            if match_type(cx, ty, &paths::MUTEX) {
+        if let ty::Adt(_, subst) = ty.sty {
+            if match_type(cx, ty, &*paths::MUTEX) {
                 let mutex_param = subst.type_at(0);
                 if let Some(atomic_name) = get_atomic_name(mutex_param) {
                     let msg = format!(
@@ -70,8 +64,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                         atomic_name
                     );
                     match mutex_param.sty {
-                        ty::TyUint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
-                        ty::TyInt(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
+                        ty::Uint(t) if t != ast::UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
+                        ty::Int(t) if t != ast::IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
                         _ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg),
                     };
                 }
@@ -82,10 +76,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
 
 fn get_atomic_name(ty: Ty<'_>) -> Option<(&'static str)> {
     match ty.sty {
-        ty::TyBool => Some("AtomicBool"),
-        ty::TyUint(_) => Some("AtomicUsize"),
-        ty::TyInt(_) => Some("AtomicIsize"),
-        ty::TyRawPtr(_) => Some("AtomicPtr"),
+        ty::Bool => Some("AtomicBool"),
+        ty::Uint(_) => Some("AtomicUsize"),
+        ty::Int(_) => Some("AtomicIsize"),
+        ty::RawPtr(_) => Some("AtomicPtr"),
         _ => None,
     }
 }
index 559aa74f9a22848d61fdfca8afff72107aa3e990..43237d82053cc6284de82205c23475156248e84d 100644 (file)
@@ -2,75 +2,76 @@
 //!
 //! This lint is **warn** by default
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sugg::Sugg;
+use crate::utils::{higher, in_macro_or_desugar, span_lint, span_lint_and_sugg};
 use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ast::LitKind;
-use syntax::codemap::Spanned;
-use crate::utils::{snippet, span_lint, span_lint_and_sugg};
-use crate::utils::sugg::Sugg;
+use syntax::source_map::Spanned;
 
-/// **What it does:** Checks for expressions of the form `if c { true } else {
-/// false }`
-/// (or vice versa) and suggest using the condition directly.
-///
-/// **Why is this bad?** Redundant code.
-///
-/// **Known problems:** Maybe false positives: Sometimes, the two branches are
-/// painstakingly documented (which we of course do not detect), so they *may*
-/// have some value. Even then, the documentation can be rewritten to match the
-/// shorter code.
-///
-/// **Example:**
-/// ```rust
-/// if x { false } else { true }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for expressions of the form `if c { true } else {
+    /// false }`
+    /// (or vice versa) and suggest using the condition directly.
+    ///
+    /// **Why is this bad?** Redundant code.
+    ///
+    /// **Known problems:** Maybe false positives: Sometimes, the two branches are
+    /// painstakingly documented (which we of course do not detect), so they *may*
+    /// have some value. Even then, the documentation can be rewritten to match the
+    /// shorter code.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if x {
+    ///     false
+    /// } else {
+    ///     true
+    /// }
+    /// ```
     pub NEEDLESS_BOOL,
     complexity,
-    "if-statements with plain booleans in the then- and else-clause, e.g. \
-     `if p { true } else { false }`"
+    "if-statements with plain booleans in the then- and else-clause, e.g., `if p { true } else { false }`"
 }
 
-/// **What it does:** Checks for expressions of the form `x == true` (or vice
-/// versa) and suggest using the variable directly.
-///
-/// **Why is this bad?** Unnecessary code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if x == true { }  // could be `if x { }`
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for expressions of the form `x == true`,
+    /// `x != true` and order comparisons such as `x < true` (or vice versa) and
+    /// suggest using the variable directly.
+    ///
+    /// **Why is this bad?** Unnecessary code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if x == true {} // could be `if x { }`
+    /// ```
     pub BOOL_COMPARISON,
     complexity,
-    "comparing a variable to a boolean, e.g. `if x == true`"
+    "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessBool;
-
-impl LintPass for NeedlessBool {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_BOOL)
-    }
-}
+declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
         use self::Expression::*;
-        if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.node {
+        if let Some((ref pred, ref then_block, Some(ref else_expr))) = higher::if_block(&e) {
             let reduce = |ret, not| {
-                let snip = Sugg::hir(cx, pred, "<predicate>");
-                let snip = if not { !snip } else { snip };
+                let mut applicability = Applicability::MachineApplicable;
+                let snip = Sugg::hir_with_applicability(cx, pred, "<predicate>", &mut applicability);
+                let mut snip = if not { !snip } else { snip };
 
-                let hint = if ret {
-                    format!("return {}", snip)
-                } else {
-                    snip.to_string()
-                };
+                if ret {
+                    snip = snip.make_return();
+                }
+
+                if parent_node_is_if_expr(&e, &cx) {
+                    snip = snip.blockify()
+                }
 
                 span_lint_and_sugg(
                     cx,
@@ -78,7 +79,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                     e.span,
                     "this if-then-else expression returns a bool literal",
                     "you can reduce it to",
-                    hint,
+                    snip.to_string(),
+                    applicability,
                 );
             };
             if let ExprKind::Block(ref then_block, _) = then_block.node {
@@ -112,70 +114,150 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct BoolComparison;
+fn parent_node_is_if_expr<'a, 'b>(expr: &Expr, cx: &LateContext<'a, 'b>) -> bool {
+    let parent_id = cx.tcx.hir().get_parent_node_by_hir_id(expr.hir_id);
+    let parent_node = cx.tcx.hir().get_by_hir_id(parent_id);
 
-impl LintPass for BoolComparison {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BOOL_COMPARISON)
+    if let rustc::hir::Node::Expr(e) = parent_node {
+        if higher::if_block(&e).is_some() {
+            return true;
+        }
     }
+
+    false
 }
 
+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) {
-        use self::Expression::*;
-        if let ExprKind::Binary(Spanned { node: BinOpKind::Eq, .. }, ref left_side, ref right_side) = e.node {
-            match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
-                (Bool(true), Other) => {
-                    let hint = snippet(cx, right_side.span, "..").into_owned();
-                    span_lint_and_sugg(
-                        cx,
-                        BOOL_COMPARISON,
-                        e.span,
-                        "equality checks against true are unnecessary",
-                        "try simplifying it as shown",
-                        hint,
-                    );
-                },
-                (Other, Bool(true)) => {
-                    let hint = snippet(cx, left_side.span, "..").into_owned();
-                    span_lint_and_sugg(
-                        cx,
-                        BOOL_COMPARISON,
-                        e.span,
-                        "equality checks against true are unnecessary",
-                        "try simplifying it as shown",
-                        hint,
-                    );
-                },
-                (Bool(false), Other) => {
-                    let hint = Sugg::hir(cx, right_side, "..");
-                    span_lint_and_sugg(
-                        cx,
-                        BOOL_COMPARISON,
-                        e.span,
+        if in_macro_or_desugar(e.span) {
+            return;
+        }
+
+        if let ExprKind::Binary(Spanned { node, .. }, ..) = e.node {
+            let ignore_case = None::<(fn(_) -> _, &str)>;
+            let ignore_no_literal = None::<(fn(_, _) -> _, &str)>;
+            match node {
+                BinOpKind::Eq => {
+                    let true_case = Some((|h| h, "equality checks against true are unnecessary"));
+                    let false_case = Some((
+                        |h: Sugg<'_>| !h,
                         "equality checks against false can be replaced by a negation",
-                        "try simplifying it as shown",
-                        (!hint).to_string(),
-                    );
+                    ));
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                },
+                BinOpKind::Ne => {
+                    let true_case = Some((
+                        |h: Sugg<'_>| !h,
+                        "inequality checks against true can be replaced by a negation",
+                    ));
+                    let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
                 },
-                (Other, Bool(false)) => {
-                    let hint = Sugg::hir(cx, left_side, "..");
+                BinOpKind::Lt => check_comparison(
+                    cx,
+                    e,
+                    ignore_case,
+                    Some((|h| h, "greater than checks against false are unnecessary")),
+                    Some((
+                        |h: Sugg<'_>| !h,
+                        "less than comparison against true can be replaced by a negation",
+                    )),
+                    ignore_case,
+                    Some((
+                        |l: Sugg<'_>, r: Sugg<'_>| (!l).bit_and(&r),
+                        "order comparisons between booleans can be simplified",
+                    )),
+                ),
+                BinOpKind::Gt => check_comparison(
+                    cx,
+                    e,
+                    Some((
+                        |h: Sugg<'_>| !h,
+                        "less than comparison against true can be replaced by a negation",
+                    )),
+                    ignore_case,
+                    ignore_case,
+                    Some((|h| h, "greater than checks against false are unnecessary")),
+                    Some((
+                        |l: Sugg<'_>, r: Sugg<'_>| l.bit_and(&(!r)),
+                        "order comparisons between booleans can be simplified",
+                    )),
+                ),
+                _ => (),
+            }
+        }
+    }
+}
+
+fn check_comparison<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    e: &'tcx Expr,
+    left_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
+    left_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
+    right_true: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
+    right_false: Option<(impl FnOnce(Sugg<'a>) -> Sugg<'a>, &str)>,
+    no_literal: Option<(impl FnOnce(Sugg<'a>, Sugg<'a>) -> Sugg<'a>, &str)>,
+) {
+    use self::Expression::*;
+
+    if let ExprKind::Binary(_, ref left_side, ref right_side) = e.node {
+        let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
+        if l_ty.is_bool() && r_ty.is_bool() {
+            let mut applicability = Applicability::MachineApplicable;
+            match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
+                (Bool(true), Other) => left_true.map_or((), |(h, m)| {
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                }),
+                (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                }),
+                (Bool(false), Other) => left_false.map_or((), |(h, m)| {
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                }),
+                (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                }),
+                (Other, Other) => no_literal.map_or((), |(h, m)| {
+                    let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
+                    let right_side = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability);
                     span_lint_and_sugg(
                         cx,
                         BOOL_COMPARISON,
                         e.span,
-                        "equality checks against false can be replaced by a negation",
+                        m,
                         "try simplifying it as shown",
-                        (!hint).to_string(),
-                    );
-                },
+                        h(left_side, right_side).to_string(),
+                        applicability,
+                    )
+                }),
                 _ => (),
             }
         }
     }
 }
 
+fn suggest_bool_comparison<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    e: &'tcx Expr,
+    expr: &Expr,
+    mut applicability: Applicability,
+    message: &str,
+    conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
+) {
+    let hint = Sugg::hir_with_applicability(cx, expr, "..", &mut applicability);
+    span_lint_and_sugg(
+        cx,
+        BOOL_COMPARISON,
+        e.span,
+        message,
+        "try simplifying it as shown",
+        conv_hint(hint).to_string(),
+        applicability,
+    );
+}
+
 enum Expression {
     Bool(bool),
     RetBool(bool),
@@ -185,14 +267,16 @@ enum Expression {
 fn fetch_bool_block(block: &Block) -> Expression {
     match (&*block.stmts, block.expr.as_ref()) {
         (&[], Some(e)) => fetch_bool_expr(&**e),
-        (&[ref e], None) => if let StmtKind::Semi(ref e, _) = e.node {
-            if let ExprKind::Ret(_) = e.node {
-                fetch_bool_expr(&**e)
+        (&[ref e], None) => {
+            if let StmtKind::Semi(ref e) = e.node {
+                if let ExprKind::Ret(_) = e.node {
+                    fetch_bool_expr(&**e)
+                } else {
+                    Expression::Other
+                }
             } else {
                 Expression::Other
             }
-        } else {
-            Expression::Other
         },
         _ => Expression::Other,
     }
@@ -201,10 +285,12 @@ fn fetch_bool_block(block: &Block) -> Expression {
 fn fetch_bool_expr(expr: &Expr) -> Expression {
     match expr.node {
         ExprKind::Block(ref block, _) => fetch_bool_block(block),
-        ExprKind::Lit(ref lit_ptr) => if let LitKind::Bool(value) = lit_ptr.node {
-            Expression::Bool(value)
-        } else {
-            Expression::Other
+        ExprKind::Lit(ref lit_ptr) => {
+            if let LitKind::Bool(value) = lit_ptr.node {
+                Expression::Bool(value)
+            } else {
+                Expression::Other
+            }
         },
         ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) {
             Expression::Bool(value) => Expression::RetBool(value),
index cb2c572743db87831c23b9690b5544028043927c..461e5885476b24ec9e51569fa1532f31f26b3506 100644 (file)
@@ -2,66 +2,53 @@
 //!
 //! This lint is **warn** by default
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, snippet_opt, span_lint_and_then};
 use if_chain::if_chain;
-use rustc::hir::{BindingAnnotation, Expr, ExprKind, MutImmutable, Pat, PatKind};
+use rustc::hir::{BindingAnnotation, Expr, ExprKind, HirId, Item, MutImmutable, Pat, PatKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
 use rustc::ty::adjustment::{Adjust, Adjustment};
-use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for address of operations (`&`) that are going to
-/// be dereferenced immediately by the compiler.
-///
-/// **Why is this bad?** Suggests that the receiver of the expression borrows
-/// the expression.
-///
-/// **Example:**
-/// ```rust
-/// let x: &i32 = &&&&&&5;
-/// ```
-///
-/// **Known problems:** This will cause false positives in code generated by `derive`.
-/// For instance in the following snippet:
-/// ```rust
-/// #[derive(Debug)]
-/// pub enum Error {
-///     Type(
-///         &'static str,
-///     ),
-/// }
-/// ```
-/// A warning will be emitted that `&'static str` should be replaced with `&'static str`,
-/// however there is nothing that can or should be done to fix this.
 declare_clippy_lint! {
+    /// **What it does:** Checks for address of operations (`&`) that are going to
+    /// be dereferenced immediately by the compiler.
+    ///
+    /// **Why is this bad?** Suggests that the receiver of the expression borrows
+    /// the expression.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: &i32 = &&&&&&5;
+    /// ```
+    ///
+    /// **Known problems:** None.
     pub NEEDLESS_BORROW,
     nursery,
     "taking a reference that is going to be automatically dereferenced"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessBorrow;
-
-impl LintPass for NeedlessBorrow {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_BORROW)
-    }
+#[derive(Default)]
+pub struct NeedlessBorrow {
+    derived_item: Option<HirId>,
 }
 
+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(e.span) {
+        if in_macro_or_desugar(e.span) || self.derived_item.is_some() {
             return;
         }
         if let ExprKind::AddrOf(MutImmutable, ref inner) = e.node {
-            if let ty::TyRef(..) = cx.tables.expr_ty(inner).sty {
+            if let ty::Ref(..) = cx.tables.expr_ty(inner).sty {
                 for adj3 in cx.tables.expr_adjustments(e).windows(3) {
                     if let [Adjustment {
-                        kind: Adjust::Deref(_),
-                        ..
+                        kind: Adjust::Deref(_), ..
                     }, Adjustment {
-                        kind: Adjust::Deref(_),
-                        ..
+                        kind: Adjust::Deref(_), ..
                     }, Adjustment {
                         kind: Adjust::Borrow(_),
                         ..
@@ -75,7 +62,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                              by the compiler",
                             |db| {
                                 if let Some(snippet) = snippet_opt(cx, inner.span) {
-                                    db.span_suggestion(e.span, "change this to", snippet);
+                                    db.span_suggestion(
+                                        e.span,
+                                        "change this to",
+                                        snippet,
+                                        Applicability::MachineApplicable,
+                                    );
                                 }
                             },
                         );
@@ -85,14 +77,14 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
         }
     }
     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
-        if in_macro(pat.span) {
+        if in_macro_or_desugar(pat.span) || self.derived_item.is_some() {
             return;
         }
         if_chain! {
-            if let PatKind::Binding(BindingAnnotation::Ref, _, name, _) = pat.node;
-            if let ty::TyRef(_, tam, mutbl) = cx.tables.pat_ty(pat).sty;
+            if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.node;
+            if let ty::Ref(_, tam, mutbl) = cx.tables.pat_ty(pat).sty;
             if mutbl == MutImmutable;
-            if let ty::TyRef(_, _, mutbl) = tam.sty;
+            if let ty::Ref(_, _, mutbl) = tam.sty;
             // only lint immutable refs, because borrowed `&mut T` cannot be moved out
             if mutbl == MutImmutable;
             then {
@@ -103,11 +95,31 @@ fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
                     "this pattern creates a reference to a reference",
                     |db| {
                         if let Some(snippet) = snippet_opt(cx, name.span) {
-                            db.span_suggestion(pat.span, "change this to", snippet);
+                            db.span_suggestion(
+                                pat.span,
+                                "change this to",
+                                snippet,
+                                Applicability::MachineApplicable,
+                            );
                         }
                     }
                 )
             }
         }
     }
+
+    fn check_item(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
+        if item.attrs.iter().any(|a| a.check_name(*sym::automatically_derived)) {
+            debug_assert!(self.derived_item.is_none());
+            self.derived_item = Some(item.hir_id);
+        }
+    }
+
+    fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, item: &'tcx Item) {
+        if let Some(id) = self.derived_item {
+            if item.hir_id == id {
+                self.derived_item = None;
+            }
+        }
+    }
 }
index 1679a9007b462df839d5b22802d60b4081d74699..b6104f6cc9a52fd01af7248e517d276914b30ae7 100644 (file)
@@ -2,66 +2,60 @@
 //!
 //! This lint is **warn** by default
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{in_macro_or_desugar, snippet, span_lint_and_then};
 use if_chain::if_chain;
 use rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind};
-use crate::utils::{in_macro, snippet, span_lint_and_then};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for useless borrowed references.
-///
-/// **Why is this bad?** It is mostly useless and make the code look more
-/// complex than it
-/// actually is.
-///
-/// **Known problems:** It seems that the `&ref` pattern is sometimes useful.
-/// For instance in the following snippet:
-/// ```rust
-/// enum Animal {
-///     Cat(u64),
-///     Dog(u64),
-/// }
-///
-/// fn foo(a: &Animal, b: &Animal) {
-///     match (a, b) {
-/// (&Animal::Cat(v), k) | (k, &Animal::Cat(v)) => (), // lifetime
-/// mismatch error
-///         (&Animal::Dog(ref c), &Animal::Dog(_)) => ()
-///     }
-/// }
-/// ```
-/// There is a lifetime mismatch error for `k` (indeed a and b have distinct
-/// lifetime).
-/// This can be fixed by using the `&ref` pattern.
-/// However, the code can also be fixed by much cleaner ways
-///
-/// **Example:**
-/// ```rust
-///     let mut v = Vec::<String>::new();
-///     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
-/// ```
-/// This closure takes a reference on something that has been matched as a
-/// reference and
-/// de-referenced.
-/// As such, it could just be |a| a.is_empty()
 declare_clippy_lint! {
+    /// **What it does:** Checks for useless borrowed references.
+    ///
+    /// **Why is this bad?** It is mostly useless and make the code look more
+    /// complex than it
+    /// actually is.
+    ///
+    /// **Known problems:** It seems that the `&ref` pattern is sometimes useful.
+    /// For instance in the following snippet:
+    /// ```rust
+    /// enum Animal {
+    ///     Cat(u64),
+    ///     Dog(u64),
+    /// }
+    ///
+    /// fn foo(a: &Animal, b: &Animal) {
+    ///     match (a, b) {
+    /// (&Animal::Cat(v), k) | (k, &Animal::Cat(v)) => (), // lifetime
+    /// mismatch error
+    ///         (&Animal::Dog(ref c), &Animal::Dog(_)) => ()
+    ///     }
+    /// }
+    /// ```
+    /// There is a lifetime mismatch error for `k` (indeed a and b have distinct
+    /// lifetime).
+    /// This can be fixed by using the `&ref` pattern.
+    /// However, the code can also be fixed by much cleaner ways
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut v = Vec::<String>::new();
+    /// let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+    /// ```
+    /// This closure takes a reference on something that has been matched as a
+    /// reference and
+    /// de-referenced.
+    /// As such, it could just be |a| a.is_empty()
     pub NEEDLESS_BORROWED_REFERENCE,
     complexity,
     "taking a needless borrowed reference"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessBorrowedRef;
-
-impl LintPass for NeedlessBorrowedRef {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_BORROWED_REFERENCE)
-    }
-}
+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(pat.span) {
+        if in_macro_or_desugar(pat.span) {
             // OK, simple enough, lints doesn't check in macro.
             return;
         }
@@ -71,13 +65,18 @@ fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
             if let PatKind::Ref(ref sub_pat, MutImmutable) = pat.node;
 
             // Check sub_pat got a `ref` keyword (excluding `ref mut`).
-            if let PatKind::Binding(BindingAnnotation::Ref, _, spanned_name, ..) = sub_pat.node;
+            if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.node;
             then {
                 span_lint_and_then(cx, NEEDLESS_BORROWED_REFERENCE, pat.span,
                                    "this pattern takes a reference on something that is being de-referenced",
                                    |db| {
                                        let hint = snippet(cx, spanned_name.span, "..").into_owned();
-                                       db.span_suggestion(pat.span, "try removing the `&ref` part and just keep", hint);
+                                       db.span_suggestion(
+                                           pat.span,
+                                           "try removing the `&ref` part and just keep",
+                                           hint,
+                                           Applicability::MachineApplicable, // snippet
+                                       );
                                    });
             }
         }
index 60ab0eaae02415a7c041d869b6e4da90fe1a15ab..8835158155b6510422e0de9877e8ab85d05e7c63 100644 (file)
@@ -2,9 +2,12 @@
 //!
 //! For example, the lint would catch
 //!
-//! ```ignore
-//! while condition() {
-//!     update_condition();
+//! ```rust
+//! let mut a = 1;
+//! let x = true;
+//!
+//! while a < 5 {
+//!     a = 6;
 //!     if x {
 //!         // ...
 //!     } else {
 //!
 //! And suggest something like this:
 //!
-//! ```ignore
-//! while condition() {
-//!     update_condition();
+//! ```rust
+//! let mut a = 1;
+//! let x = true;
+//!
+//! while a < 5 {
+//!     a = 6;
 //!     if x {
 //!         // ...
 //!         println!("Hello, world");
 //! ```
 //!
 //! This lint is **warn** by default.
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::ast;
-use syntax::codemap::{original_sp, DUMMY_SP};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use std::borrow::Cow;
+use syntax::ast;
+use syntax::source_map::{original_sp, DUMMY_SP};
 
-use crate::utils::{in_macro, snippet, snippet_block, span_help_and_lint, trim_multiline};
+use crate::utils::{in_macro_or_desugar, snippet, snippet_block, span_help_and_lint, trim_multiline};
 
-/// **What it does:** The lint checks for `if`-statements appearing in loops
-/// that contain a `continue` statement in either their main blocks or their
-/// `else`-blocks, when omitting the `else`-block possibly with some
-/// rearrangement of code can make the code easier to understand.
-///
-/// **Why is this bad?** Having explicit `else` blocks for `if` statements
-/// containing `continue` in their THEN branch adds unnecessary branching and
-/// nesting to the code. Having an else block containing just `continue` can
-/// also be better written by grouping the statements following the whole `if`
-/// statement within the THEN block and omitting the else block completely.
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// while condition() {
-///     update_condition();
-///     if x {
-///         // ...
-///     } else {
-///         continue;
-///     }
-///     println!("Hello, world");
-/// }
-/// ```
-///
-/// Could be rewritten as
-///
-/// ```rust
-/// while condition() {
-///     update_condition();
-///     if x {
-///         // ...
-///         println!("Hello, world");
-///     }
-/// }
-/// ```
-///
-/// As another example, the following code
-///
-/// ```rust
-/// loop {
-///     if waiting() {
-///         continue;
-///     } else {
-///         // Do something useful
-///     }
-/// }
-/// ```
-/// Could be rewritten as
-///
-/// ```rust
-/// loop {
-///     if waiting() {
-///         continue;
-///     }
-///     // Do something useful
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** The lint checks for `if`-statements appearing in loops
+    /// that contain a `continue` statement in either their main blocks or their
+    /// `else`-blocks, when omitting the `else`-block possibly with some
+    /// rearrangement of code can make the code easier to understand.
+    ///
+    /// **Why is this bad?** Having explicit `else` blocks for `if` statements
+    /// containing `continue` in their THEN branch adds unnecessary branching and
+    /// nesting to the code. Having an else block containing just `continue` can
+    /// also be better written by grouping the statements following the whole `if`
+    /// statement within the THEN block and omitting the else block completely.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// while condition() {
+    ///     update_condition();
+    ///     if x {
+    ///         // ...
+    ///     } else {
+    ///         continue;
+    ///     }
+    ///     println!("Hello, world");
+    /// }
+    /// ```
+    ///
+    /// Could be rewritten as
+    ///
+    /// ```rust
+    /// while condition() {
+    ///     update_condition();
+    ///     if x {
+    ///         // ...
+    ///         println!("Hello, world");
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// As another example, the following code
+    ///
+    /// ```rust
+    /// loop {
+    ///     if waiting() {
+    ///         continue;
+    ///     } else {
+    ///         // Do something useful
+    ///     }
+    /// }
+    /// ```
+    /// Could be rewritten as
+    ///
+    /// ```rust
+    /// loop {
+    ///     if waiting() {
+    ///         continue;
+    ///     }
+    ///     // Do something useful
+    /// }
+    /// ```
     pub NEEDLESS_CONTINUE,
     pedantic,
     "`continue` statements that can be replaced by a rearrangement of code"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessContinue;
-
-impl LintPass for NeedlessContinue {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_CONTINUE)
-    }
-}
+declare_lint_pass!(NeedlessContinue => [NEEDLESS_CONTINUE]);
 
 impl EarlyLintPass for NeedlessContinue {
     fn check_expr(&mut self, ctx: &EarlyContext<'_>, expr: &ast::Expr) {
-        if !in_macro(expr.span) {
+        if !in_macro_or_desugar(expr.span) {
             check_and_warn(ctx, expr);
         }
     }
@@ -171,37 +170,50 @@ fn check_expr(&mut self, ctx: &EarlyContext<'_>, expr: &ast::Expr) {
 /// - The expression is a `continue` node.
 /// - The expression node is a block with the first statement being a
 /// `continue`.
-///
-fn needless_continue_in_else(else_expr: &ast::Expr) -> bool {
+fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
     match else_expr.node {
-        ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block),
-        ast::ExprKind::Continue(_) => true,
+        ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
+        ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()),
         _ => false,
     }
 }
 
-fn is_first_block_stmt_continue(block: &ast::Block) -> bool {
+fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
     block.stmts.get(0).map_or(false, |stmt| match stmt.node {
-        ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => if let ast::ExprKind::Continue(_) = e.node {
-            true
-        } else {
-            false
+        ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
+            if let ast::ExprKind::Continue(ref l) = e.node {
+                compare_labels(label, l.as_ref())
+            } else {
+                false
+            }
         },
         _ => false,
     })
 }
 
+/// If the `continue` has a label, check it matches the label of the loop.
+fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::Label>) -> bool {
+    match (loop_label, continue_label) {
+        // `loop { continue; }` or `'a loop { continue; }`
+        (_, None) => true,
+        // `loop { continue 'a; }`
+        (None, _) => false,
+        // `'a loop { continue 'a; }` or `'a loop { continue 'b; }`
+        (Some(x), Some(y)) => x.ident == y.ident,
+    }
+}
+
 /// If `expr` is a loop expression (while/while let/for/loop), calls `func` with
 /// the AST object representing the loop block of `expr`.
 fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
 where
-    F: FnMut(&ast::Block),
+    F: FnMut(&ast::Block, Option<&ast::Label>),
 {
     match expr.node {
-        ast::ExprKind::While(_, ref loop_block, _) |
-        ast::ExprKind::WhileLet(_, _, ref loop_block, _) |
-        ast::ExprKind::ForLoop(_, _, ref loop_block, _) |
-        ast::ExprKind::Loop(ref loop_block, _) => func(loop_block),
+        ast::ExprKind::While(_, ref loop_block, ref label)
+        | ast::ExprKind::WhileLet(_, _, ref loop_block, ref label)
+        | ast::ExprKind::ForLoop(_, _, ref loop_block, ref label)
+        | ast::ExprKind::Loop(ref loop_block, ref label) => func(loop_block, label.as_ref()),
         _ => {},
     }
 }
@@ -214,7 +226,6 @@ fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
 /// - The `if` condition expression,
 /// - The `then` block, and
 /// - The `else` expression.
-///
 fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
 where
     F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
@@ -264,7 +275,6 @@ struct LintData<'a> {
 const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \
                                    block, like so:\n";
 
-
 fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
     // snip    is the whole *help* message that appears after the warning.
     // message is the warning message.
@@ -284,7 +294,11 @@ fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str
     span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip);
 }
 
-fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String {
+fn suggestion_snippet_for_continue_inside_if<'a>(
+    ctx: &EarlyContext<'_>,
+    data: &'a LintData<'_>,
+    header: &str,
+) -> String {
     let cond_code = snippet(ctx, data.if_cond.span, "..");
 
     let if_code = format!("if {} {{\n    continue;\n}}\n", cond_code);
@@ -301,7 +315,11 @@ fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &
     ret
 }
 
-fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String {
+fn suggestion_snippet_for_continue_inside_else<'a>(
+    ctx: &EarlyContext<'_>,
+    data: &'a LintData<'_>,
+    header: &str,
+) -> String {
     let cond_code = snippet(ctx, data.if_cond.span, "..");
     let mut if_code = format!("if {} {{\n", cond_code);
 
@@ -333,7 +351,7 @@ fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext<'_>, data:
 }
 
 fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
-    with_loop_block(expr, |loop_block| {
+    with_loop_block(expr, |loop_block, label| {
         for (i, stmt) in loop_block.stmts.iter().enumerate() {
             with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
                 let data = &LintData {
@@ -344,9 +362,14 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
                     else_expr,
                     block_stmts: &loop_block.stmts,
                 };
-                if needless_continue_in_else(else_expr) {
-                    emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock);
-                } else if is_first_block_stmt_continue(then_block) {
+                if needless_continue_in_else(else_expr, label) {
+                    emit_warning(
+                        ctx,
+                        data,
+                        DROP_ELSE_BLOCK_AND_MERGE_MSG,
+                        LintType::ContinueInsideElseBlock,
+                    );
+                } else if is_first_block_stmt_continue(then_block, label) {
                     emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
                 }
             });
@@ -358,10 +381,10 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
 /// continues eating till a non-whitespace character is found.
 /// e.g., the string
 ///
-/// ```
-///     {
-///         let x = 5;
-///     }
+/// ```rust
+/// {
+///     let x = 5;
+/// }
 /// ```
 ///
 /// is transformed to
@@ -403,7 +426,6 @@ pub fn erode_from_back(s: &str) -> String {
 ///             inside_a_block();
 ///         }
 /// ```
-///
 pub fn erode_from_front(s: &str) -> String {
     s.chars()
         .skip_while(|c| c.is_whitespace())
index 82e85f3453a1526d5c1ebaaf74c37a2d3cb4feca..9c380e34aa6788475db46efb4b8c9cbc389c155e 100644 (file)
@@ -1,66 +1,70 @@
+use crate::utils::ptr::get_spans;
+use crate::utils::sym;
+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,
+};
+use if_chain::if_chain;
 use matches::matches;
-use rustc::hir::*;
-use rustc::hir::map::*;
 use rustc::hir::intravisit::FnKind;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use rustc::ty::{self, RegionKind, TypeFoldable};
-use rustc::traits;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
+use rustc::traits;
+use rustc::ty::{self, RegionKind, TypeFoldable};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
 use rustc_target::spec::abi::Abi;
-use syntax::ast::NodeId;
-use syntax_pos::Span;
-use syntax::errors::DiagnosticBuilder;
-use crate::utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
-            snippet, snippet_opt, span_lint_and_then};
-use crate::utils::ptr::get_spans;
-use std::collections::{HashMap, HashSet};
 use std::borrow::Cow;
+use syntax::ast::Attribute;
+use syntax::errors::DiagnosticBuilder;
+use syntax_pos::Span;
 
-/// **What it does:** Checks for functions taking arguments by value, but not
-/// consuming them in its
-/// body.
-///
-/// **Why is this bad?** Taking arguments by reference is more flexible and can
-/// sometimes avoid
-/// unnecessary allocations.
-///
-/// **Known problems:**
-/// * This lint suggests taking an argument by reference,
-/// however sometimes it is better to let users decide the argument type
-/// (by using `Borrow` trait, for example), depending on how the function is used.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(v: Vec<i32>) {
-///     assert_eq!(v.len(), 42);
-/// }
-/// // should be
-/// fn foo(v: &[i32]) {
-///     assert_eq!(v.len(), 42);
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for functions taking arguments by value, but not
+    /// consuming them in its
+    /// body.
+    ///
+    /// **Why is this bad?** Taking arguments by reference is more flexible and can
+    /// sometimes avoid
+    /// unnecessary allocations.
+    ///
+    /// **Known problems:**
+    /// * This lint suggests taking an argument by reference,
+    /// however sometimes it is better to let users decide the argument type
+    /// (by using `Borrow` trait, for example), depending on how the function is used.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(v: Vec<i32>) {
+    ///     assert_eq!(v.len(), 42);
+    /// }
+    /// // should be
+    /// fn foo(v: &[i32]) {
+    ///     assert_eq!(v.len(), 42);
+    /// }
+    /// ```
     pub NEEDLESS_PASS_BY_VALUE,
-    style,
+    pedantic,
     "functions taking arguments by value, but not consuming them in its body"
 }
 
-pub struct NeedlessPassByValue;
-
-impl LintPass for NeedlessPassByValue {
-    fn get_lints(&self) -> LintArray {
-        lint_array![NEEDLESS_PASS_BY_VALUE]
-    }
-}
+declare_lint_pass!(NeedlessPassByValue => [NEEDLESS_PASS_BY_VALUE]);
 
 macro_rules! need {
-    ($e: expr) => { if let Some(x) = $e { x } else { return; } };
+    ($e: expr) => {
+        if let Some(x) = $e {
+            x
+        } else {
+            return;
+        }
+    };
 }
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
+    #[allow(clippy::too_many_lines)]
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -68,29 +72,28 @@ fn check_fn(
         decl: &'tcx FnDecl,
         body: &'tcx Body,
         span: Span,
-        node_id: NodeId,
+        hir_id: HirId,
     ) {
-        if in_macro(span) {
+        if in_macro_or_desugar(span) {
             return;
         }
 
         match kind {
             FnKind::ItemFn(.., header, _, attrs) => {
-                if header.abi != Abi::Rust {
+                if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
-                for a in attrs {
-                    if a.meta_item_list().is_some() && a.name() == "proc_macro_derive" {
-                        return;
-                    }
-                }
             },
             FnKind::Method(..) => (),
             _ => return,
         }
 
         // Exclude non-inherent impls
-        if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(node_id)) {
+        if let Some(Node::Item(item)) = cx
+            .tcx
+            .hir()
+            .find_by_hir_id(cx.tcx.hir().get_parent_node_by_hir_id(hir_id))
+        {
             if matches!(item.node, ItemKind::Impl(_, _, _, _, Some(_), _, _) |
                 ItemKind::Trait(..))
             {
@@ -99,23 +102,24 @@ fn check_fn(
         }
 
         // Allow `Borrow` or functions to be taken by value
-        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
+        let borrow_trait = need!(get_trait_def_id(cx, &*paths::BORROW_TRAIT));
         let whitelisted_traits = [
             need!(cx.tcx.lang_items().fn_trait()),
             need!(cx.tcx.lang_items().fn_once_trait()),
             need!(cx.tcx.lang_items().fn_mut_trait()),
-            need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT))
+            need!(get_trait_def_id(cx, &*paths::RANGE_ARGUMENT_TRAIT)),
         ];
 
         let sized_trait = need!(cx.tcx.lang_items().sized_trait());
 
-        let fn_def_id = cx.tcx.hir.local_def_id(node_id);
+        let fn_def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id);
 
         let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
             .filter(|p| !p.is_global())
             .filter_map(|pred| {
                 if let ty::Predicate::Trait(poly_trait_ref) = pred {
-                    if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() {
+                    if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
+                    {
                         return None;
                     }
                     Some(poly_trait_ref)
@@ -142,12 +146,7 @@ fn check_fn(
         let fn_sig = cx.tcx.fn_sig(fn_def_id);
         let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);
 
-        for (idx, ((input, &ty), arg)) in decl.inputs
-            .iter()
-            .zip(fn_sig.inputs())
-            .zip(&body.arguments)
-            .enumerate()
-        {
+        for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments).enumerate() {
             // All spans generated from a proc-macro invocation are the same...
             if span == input.span {
                 return;
@@ -155,16 +154,17 @@ fn check_fn(
 
             // Ignore `self`s.
             if idx == 0 {
-                if let PatKind::Binding(_, _, ident, ..) = arg.pat.node {
+                if let PatKind::Binding(.., ident, _) = arg.pat.node {
                     if ident.as_str() == "self" {
                         continue;
                     }
                 }
             }
 
+            //
             // * Exclude a type that is specifically bounded by `Borrow`.
-            // * Exclude a type whose reference also fulfills its bound.
-            //   (e.g. `std::convert::AsRef`, `serde::Serialize`)
+            // * Exclude a type whose reference also fulfills its bound. (e.g., `std::convert::AsRef`,
+            //   `serde::Serialize`)
             let (implements_borrow_trait, all_borrowable_trait) = {
                 let preds = preds
                     .iter()
@@ -173,18 +173,18 @@ fn check_fn(
 
                 (
                     preds.iter().any(|t| t.def_id() == borrow_trait),
-                    !preds.is_empty() && preds.iter().all(|t| {
-                        implements_trait(
-                            cx,
-                            cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
-                            t.def_id(),
-                            &t.skip_binder()
-                                .input_types()
+                    !preds.is_empty()
+                        && preds.iter().all(|t| {
+                            let ty_params = &t
+                                .skip_binder()
+                                .trait_ref
+                                .substs
+                                .iter()
                                 .skip(1)
-                                .map(|ty| ty.into())
-                                .collect::<Vec<_>>(),
-                        )
-                    }),
+                                .cloned()
+                                .collect::<Vec<_>>();
+                            implements_trait(cx, cx.tcx.mk_imm_ref(&RegionKind::ReEmpty, ty), t.def_id(), ty_params)
+                        }),
                 )
             };
 
@@ -205,8 +205,8 @@ fn check_fn(
 
                     // Dereference suggestion
                     let sugg = |db: &mut DiagnosticBuilder<'_>| {
-                        if let ty::TypeVariants::TyAdt(def, ..) = ty.sty {
-                            if let Some(span) = cx.tcx.hir.span_if_local(def.did) {
+                        if let ty::Adt(def, ..) = ty.sty {
+                            if let Some(span) = cx.tcx.hir().span_if_local(def.did) {
                                 if cx.param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
                                     db.span_help(span, "consider marking this type as Copy");
                                 }
@@ -215,22 +215,25 @@ fn check_fn(
 
                         let deref_span = spans_need_deref.get(&canonical_id);
                         if_chain! {
-                            if match_type(cx, ty, &paths::VEC);
+                            if match_type(cx, ty, &*paths::VEC);
                             if let Some(clone_spans) =
-                                get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
+                                get_spans(cx, Some(body.id()), idx, &[(*sym::clone, ".to_owned()")]);
                             if let TyKind::Path(QPath::Resolved(_, ref path)) = input.node;
                             if let Some(elem_ty) = path.segments.iter()
-                                .find(|seg| seg.ident.name == "Vec")
+                                .find(|seg| seg.ident.name == *sym::Vec)
                                 .and_then(|ps| ps.args.as_ref())
                                 .map(|params| params.args.iter().find_map(|arg| match arg {
                                     GenericArg::Type(ty) => Some(ty),
-                                    GenericArg::Lifetime(_) => None,
+                                    _ => None,
                                 }).unwrap());
                             then {
                                 let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
-                                db.span_suggestion(input.span,
-                                                "consider changing the type to",
-                                                slice_ty);
+                                db.span_suggestion(
+                                    input.span,
+                                    "consider changing the type to",
+                                    slice_ty,
+                                    Applicability::Unspecified,
+                                );
 
                                 for (span, suggestion) in clone_spans {
                                     db.span_suggestion(
@@ -240,7 +243,8 @@ fn check_fn(
                                                 "change the call to".into(),
                                                 |x| Cow::from(format!("change `{}` to", x)),
                                             ),
-                                        suggestion.into()
+                                        suggestion.into(),
+                                        Applicability::Unspecified,
                                     );
                                 }
 
@@ -250,10 +254,15 @@ fn check_fn(
                             }
                         }
 
-                        if match_type(cx, ty, &paths::STRING) {
+                        if match_type(cx, ty, &*paths::STRING) {
                             if let Some(clone_spans) =
-                                get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
-                                db.span_suggestion(input.span, "consider changing the type to", "&str".to_string());
+                                get_spans(cx, Some(body.id()), idx, &[(*sym::clone, ".to_string()"), (*sym::as_str, "")]) {
+                                db.span_suggestion(
+                                    input.span,
+                                    "consider changing the type to",
+                                    "&str".to_string(),
+                                    Applicability::Unspecified,
+                                );
 
                                 for (span, suggestion) in clone_spans {
                                     db.span_suggestion(
@@ -264,6 +273,7 @@ fn check_fn(
                                                 |x| Cow::from(format!("change `{}` to", x))
                                             ),
                                         suggestion.into(),
+                                        Applicability::Unspecified,
                                     );
                                 }
 
@@ -300,24 +310,33 @@ fn check_fn(
     }
 }
 
+/// Functions marked with these attributes must have the exact signature.
+fn requires_exact_signature(attrs: &[Attribute]) -> bool {
+    attrs.iter().any(|attr| {
+        [*sym::proc_macro, *sym::proc_macro_attribute, *sym::proc_macro_derive]
+            .iter()
+            .any(|&allow| attr.check_name(allow))
+    })
+}
+
 struct MovedVariablesCtxt<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
-    moved_vars: HashSet<NodeId>,
+    moved_vars: FxHashSet<HirId>,
     /// Spans which need to be prefixed with `*` for dereferencing the
     /// suggested additional reference.
-    spans_need_deref: HashMap<NodeId, HashSet<Span>>,
+    spans_need_deref: FxHashMap<HirId, FxHashSet<Span>>,
 }
 
 impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
     fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
         Self {
             cx,
-            moved_vars: HashSet::new(),
-            spans_need_deref: HashMap::new(),
+            moved_vars: FxHashSet::default(),
+            spans_need_deref: FxHashMap::default(),
         }
     }
 
-    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: &mc::cmt_<'tcx>) {
+    fn move_common(&mut self, _consume_id: HirId, _span: Span, cmt: &mc::cmt_<'tcx>) {
         let cmt = unwrap_downcast_or_interior(cmt);
 
         if let mc::Categorization::Local(vid) = cmt.cat {
@@ -329,36 +348,35 @@ fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: &mc::cmt_<'tcx>) {
         let cmt = unwrap_downcast_or_interior(cmt);
 
         if let mc::Categorization::Local(vid) = cmt.cat {
-            let mut id = matched_pat.id;
+            let mut id = matched_pat.hir_id;
             loop {
-                let parent = self.cx.tcx.hir.get_parent_node(id);
+                let parent = self.cx.tcx.hir().get_parent_node_by_hir_id(id);
                 if id == parent {
                     // no parent
                     return;
                 }
                 id = parent;
 
-                if let Some(node) = self.cx.tcx.hir.find(id) {
+                if let Some(node) = self.cx.tcx.hir().find_by_hir_id(id) {
                     match node {
-                        map::Node::NodeExpr(e) => {
+                        Node::Expr(e) => {
                             // `match` and `if let`
                             if let ExprKind::Match(ref c, ..) = e.node {
                                 self.spans_need_deref
                                     .entry(vid)
-                                    .or_insert_with(HashSet::new)
+                                    .or_insert_with(FxHashSet::default)
                                     .insert(c.span);
                             }
                         },
 
-                        map::Node::NodeStmt(s) => {
+                        Node::Stmt(s) => {
                             // `let <pat> = x;`
                             if_chain! {
-                                if let StmtKind::Decl(ref decl, _) = s.node;
-                                if let DeclKind::Local(ref local) = decl.node;
+                                if let StmtKind::Local(ref local) = s.node;
                                 then {
                                     self.spans_need_deref
                                         .entry(vid)
-                                        .or_insert_with(HashSet::new)
+                                        .or_insert_with(FxHashSet::default)
                                         .insert(local.init
                                             .as_ref()
                                             .map(|e| e.span)
@@ -376,7 +394,7 @@ fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: &mc::cmt_<'tcx>) {
 }
 
 impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
-    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) {
+    fn consume(&mut self, consume_id: HirId, consume_span: Span, cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) {
         if let euv::ConsumeMode::Move(_) = mode {
             self.move_common(consume_id, consume_span, cmt);
         }
@@ -384,7 +402,7 @@ fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: &mc::cmt_<'tc
 
     fn matched_pat(&mut self, matched_pat: &Pat, cmt: &mc::cmt_<'tcx>, mode: euv::MatchMode) {
         if let euv::MatchMode::MovingMatch = mode {
-            self.move_common(matched_pat.id, matched_pat.span, cmt);
+            self.move_common(matched_pat.hir_id, matched_pat.span, cmt);
         } else {
             self.non_moving_pat(matched_pat, cmt);
         }
@@ -392,18 +410,26 @@ fn matched_pat(&mut self, matched_pat: &Pat, cmt: &mc::cmt_<'tcx>, mode: euv::Ma
 
     fn consume_pat(&mut self, consume_pat: &Pat, cmt: &mc::cmt_<'tcx>, mode: euv::ConsumeMode) {
         if let euv::ConsumeMode::Move(_) = mode {
-            self.move_common(consume_pat.id, consume_pat.span, cmt);
+            self.move_common(consume_pat.hir_id, consume_pat.span, cmt);
         }
     }
 
-    fn borrow(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, _: euv::LoanCause) {}
+    fn borrow(
+        &mut self,
+        _: HirId,
+        _: Span,
+        _: &mc::cmt_<'tcx>,
+        _: ty::Region<'_>,
+        _: ty::BorrowKind,
+        _: euv::LoanCause,
+    ) {
+    }
 
-    fn mutate(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {}
+    fn mutate(&mut self, _: HirId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {}
 
-    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
+    fn decl_without_init(&mut self, _: HirId, _: Span) {}
 }
 
-
 fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt_<'tcx> {
     loop {
         match cmt.cat {
@@ -412,5 +438,5 @@ fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt
             },
             _ => return (*cmt).clone(),
         }
-    };
+    }
 }
index 52c4c6e52371c749424a32b3d21419b456511ca4..316395acf263bc69810591f35622c0b19d3301f0 100644 (file)
@@ -1,41 +1,38 @@
+use crate::utils::span_lint;
+use rustc::hir::{Expr, ExprKind};
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
 use rustc::ty;
-use rustc::hir::{Expr, ExprKind};
-use crate::utils::span_lint;
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for needlessly including a base struct on update
-/// when all fields are changed anyway.
-///
-/// **Why is this bad?** This will cost resources (because the base has to be
-/// somewhere), and make the code less readable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// Point { x: 1, y: 0, ..zero_point }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for needlessly including a base struct on update
+    /// when all fields are changed anyway.
+    ///
+    /// **Why is this bad?** This will cost resources (because the base has to be
+    /// somewhere), and make the code less readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// Point {
+    ///     x: 1,
+    ///     y: 0,
+    ///     ..zero_point
+    /// }
+    /// ```
     pub NEEDLESS_UPDATE,
     complexity,
     "using `Foo { ..base }` when there are no missing fields"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_UPDATE)
-    }
-}
+declare_lint_pass!(NeedlessUpdate => [NEEDLESS_UPDATE]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessUpdate {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::Struct(_, ref fields, Some(ref base)) = expr.node {
             let ty = cx.tables.expr_ty(expr);
-            if let ty::TyAdt(def, _) = ty.sty {
+            if let ty::Adt(def, _) = ty.sty {
                 if fields.len() == def.non_enum_variant().fields.len() {
                     span_lint(
                         cx,
index f53e2cb0cce803d9ad521de9d4ded66248301d59..7cc1b576cfa80dd87aeff2525b085748a285c106 100644 (file)
@@ -1,57 +1,50 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
 use crate::utils::{self, paths, span_lint};
 
-/// **What it does:**
-/// Checks for the usage of negated comparison operators on types which only implement
-/// `PartialOrd` (e.g. `f64`).
-///
-/// **Why is this bad?**
-/// These operators make it easy to forget that the underlying types actually allow not only three
-/// potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is
-/// especially easy to miss if the operator based comparison result is negated.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// use std::cmp::Ordering;
-/// 
-/// // Bad
-/// let a = 1.0;
-/// let b = std::f64::NAN;
-///
-/// let _not_less_or_equal = !(a <= b);
-///
-/// // Good
-/// let a = 1.0;
-/// let b = std::f64::NAN;
-///
-/// let _not_less_or_equal = match a.partial_cmp(&b) {
-///     None | Some(Ordering::Greater) => true,
-///     _ => false,
-/// };
-/// ```
 declare_clippy_lint! {
+    /// **What it does:**
+    /// Checks for the usage of negated comparison operators on types which only implement
+    /// `PartialOrd` (e.g., `f64`).
+    ///
+    /// **Why is this bad?**
+    /// These operators make it easy to forget that the underlying types actually allow not only three
+    /// potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is
+    /// especially easy to miss if the operator based comparison result is negated.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// use std::cmp::Ordering;
+    ///
+    /// // Bad
+    /// let a = 1.0;
+    /// let b = std::f64::NAN;
+    ///
+    /// let _not_less_or_equal = !(a <= b);
+    ///
+    /// // Good
+    /// let a = 1.0;
+    /// let b = std::f64::NAN;
+    ///
+    /// let _not_less_or_equal = match a.partial_cmp(&b) {
+    ///     None | Some(Ordering::Greater) => true,
+    ///     _ => false,
+    /// };
+    /// ```
     pub NEG_CMP_OP_ON_PARTIAL_ORD,
     complexity,
     "The use of negated comparison operators on partially ordered types may produce confusing code."
 }
 
-pub struct NoNegCompOpForPartialOrd;
-
-impl LintPass for NoNegCompOpForPartialOrd {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEG_CMP_OP_ON_PARTIAL_ORD)
-    }
-}
+declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd {
-
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
 
@@ -65,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 let ty = cx.tables.expr_ty(left);
 
                 let implements_ord = {
-                    if let Some(id) = utils::get_trait_def_id(cx, &paths::ORD) {
+                    if let Some(id) = utils::get_trait_def_id(cx, &*paths::ORD) {
                         utils::implements_trait(cx, ty, id, &[])
                     } else {
                         return;
@@ -73,7 +66,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 };
 
                 let implements_partial_ord = {
-                    if let Some(id) = utils::get_trait_def_id(cx, &paths::PARTIAL_ORD) {
+                    if let Some(id) = utils::get_trait_def_id(cx, &*paths::PARTIAL_ORD) {
                         utils::implements_trait(cx, ty, id, &[])
                     } else {
                         return;
index c056ff46178b6af646d24fd238426227ba693be4..c235661a432be3dab1200498d5489490b42a8325 100644 (file)
@@ -1,41 +1,41 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
-use syntax::codemap::{Span, Spanned};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::source_map::{Span, Spanned};
 
 use crate::consts::{self, Constant};
 use crate::utils::span_lint;
 
-/// **What it does:** Checks for multiplication by -1 as a form of negation.
-///
-/// **Why is this bad?** It's more readable to just negate.
-///
-/// **Known problems:** This only catches integers (for now).
-///
-/// **Example:**
-/// ```rust
-/// x * -1
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for multiplication by -1 as a form of negation.
+    ///
+    /// **Why is this bad?** It's more readable to just negate.
+    ///
+    /// **Known problems:** This only catches integers (for now).
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// x * -1
+    /// ```
     pub NEG_MULTIPLY,
     style,
     "multiplying integers with -1"
 }
 
-#[derive(Copy, Clone)]
-pub struct NegMultiply;
-
-impl LintPass for NegMultiply {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEG_MULTIPLY)
-    }
-}
+declare_lint_pass!(NegMultiply => [NEG_MULTIPLY]);
 
-#[allow(match_same_arms)]
+#[allow(clippy::match_same_arms)]
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref l, ref r) = e.node {
+        if let ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Mul, ..
+            },
+            ref l,
+            ref r,
+        ) = e.node
+        {
             match (&l.node, &r.node) {
                 (&ExprKind::Unary(..), &ExprKind::Unary(..)) => (),
                 (&ExprKind::Unary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r),
index eeb131959e9a2fc94bf3ecad96cf054f8d584677..7e2899bc7a9892a7fb8d4cd8375ca0a76fb21f14 100644 (file)
-use rustc::hir::def_id::DefId;
-use rustc::hir;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use rustc::ty::{self, Ty};
-use syntax::codemap::Span;
 use crate::utils::paths;
-use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then};
 use crate::utils::sugg::DiagnosticBuilderExt;
+use crate::utils::sym;
+use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_hir_and_then};
+use if_chain::if_chain;
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::util::nodemap::NodeSet;
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for types with a `fn new() -> Self` method and no
-/// implementation of
-/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
-///
-/// **Why is this bad?** The user might expect to be able to use
-/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
-/// type can be constructed without arguments.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-///
-/// ```rust,ignore
-/// struct Foo(Bar);
-///
-/// impl Foo {
-///     fn new() -> Self {
-///         Foo(Bar::new())
-///     }
-/// }
-/// ```
-///
-/// Instead, use:
-///
-/// ```rust
-/// struct Foo(Bar);
-///
-/// impl Default for Foo {
-///     fn default() -> Self {
-///         Foo(Bar::new())
-///     }
-/// }
-/// ```
-///
-/// You can also have `new()` call `Default::default()`.
 declare_clippy_lint! {
+    /// **What it does:** Checks for types with a `fn new() -> Self` method and no
+    /// implementation of
+    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
+    ///
+    /// It detects both the case when a manual
+    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
+    /// implementation is required and also when it can be created with
+    /// `#[derive(Default)]`
+    ///
+    /// **Why is this bad?** The user might expect to be able to use
+    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
+    /// type can be constructed without arguments.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    ///
+    /// ```ignore
+    /// struct Foo(Bar);
+    ///
+    /// impl Foo {
+    ///     fn new() -> Self {
+    ///         Foo(Bar::new())
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Instead, use:
+    ///
+    /// ```ignore
+    /// struct Foo(Bar);
+    ///
+    /// impl Default for Foo {
+    ///     fn default() -> Self {
+    ///         Foo(Bar::new())
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Or, if
+    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
+    /// can be derived by `#[derive(Default)]`:
+    ///
+    /// ```rust
+    /// struct Foo;
+    ///
+    /// impl Foo {
+    ///     fn new() -> Self {
+    ///         Foo
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Instead, use:
+    ///
+    /// ```rust
+    /// #[derive(Default)]
+    /// struct Foo;
+    ///
+    /// impl Foo {
+    ///     fn new() -> Self {
+    ///         Foo
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// You can also have `new()` call `Default::default()`.
     pub NEW_WITHOUT_DEFAULT,
     style,
     "`fn new() -> Self` method without `Default` implementation"
 }
 
-/// **What it does:** Checks for types with a `fn new() -> Self` method
-/// and no implementation of
-/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html),
-/// where the `Default` can be derived by `#[derive(Default)]`.
-///
-/// **Why is this bad?** The user might expect to be able to use
-/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
-/// type can be constructed without arguments.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-///
-/// ```rust,ignore
-/// struct Foo;
-///
-/// impl Foo {
-///     fn new() -> Self {
-///         Foo
-///     }
-/// }
-/// ```
-///
-/// Just prepend `#[derive(Default)]` before the `struct` definition.
-declare_clippy_lint! {
-    pub NEW_WITHOUT_DEFAULT_DERIVE,
-    style,
-    "`fn new() -> Self` without `#[derive]`able `Default` implementation"
+#[derive(Clone, Default)]
+pub struct NewWithoutDefault {
+    impling_types: Option<NodeSet>,
 }
 
-#[derive(Copy, Clone)]
-pub struct NewWithoutDefault;
-
-impl LintPass for NewWithoutDefault {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEW_WITHOUT_DEFAULT, NEW_WITHOUT_DEFAULT_DERIVE)
-    }
-}
+impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
         if let hir::ItemKind::Impl(_, _, _, _, None, _, ref items) = item.node {
             for assoc_item in items {
                 if let hir::AssociatedItemKind::Method { has_self: false } = assoc_item.kind {
-                    let impl_item = cx.tcx.hir.impl_item(assoc_item.id);
+                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                     if in_external_macro(cx.sess(), impl_item.span) {
                         return;
                     }
                     if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
                         let name = impl_item.ident.name;
-                        let id = impl_item.id;
+                        let id = impl_item.hir_id;
                         if sig.header.constness == hir::Constness::Const {
                             // can't be implemented by default
                             return;
                         }
+                        if sig.header.unsafety == hir::Unsafety::Unsafe {
+                            // can't be implemented for unsafe new
+                            return;
+                        }
                         if impl_item.generics.params.iter().any(|gen| match gen.kind {
                             hir::GenericParamKind::Type { .. } => true,
-                            _ => false
+                            _ => false,
                         }) {
                             // when the result of `new()` depends on a type parameter we should not require
                             // an
                             // impl of `Default`
                             return;
                         }
-                        if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
-                            let self_ty = cx.tcx
-                                .type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)));
+                        if sig.decl.inputs.is_empty() && name == *sym::new && cx.access_levels.is_reachable(id) {
+                            let self_did = cx.tcx.hir().local_def_id_from_hir_id(cx.tcx.hir().get_parent_item(id));
+                            let self_ty = cx.tcx.type_of(self_did);
                             if_chain! {
                                 if same_tys(cx, self_ty, return_ty(cx, id));
-                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
-                                if !implements_trait(cx, self_ty, default_trait_id, &[]);
+                                if let Some(default_trait_id) = get_trait_def_id(cx, &*paths::DEFAULT_TRAIT);
                                 then {
+                                    if self.impling_types.is_none() {
+                                        let mut impls = NodeSet::default();
+                                        cx.tcx.for_each_impl(default_trait_id, |d| {
+                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
+                                                if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) {
+                                                    impls.insert(node_id);
+                                                }
+                                            }
+                                        });
+                                        self.impling_types = Some(impls);
+                                    }
+
+                                    // Check if a Default implementation exists for the Self type, regardless of
+                                    // generics
+                                    if_chain! {
+                                        if let Some(ref impling_types) = self.impling_types;
+                                        if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def();
+                                        if self_def.did.is_local();
+                                        then {
+                                            let self_id = cx.tcx.hir().local_def_id_to_node_id(self_def.did.to_local());
+                                            if impling_types.contains(&self_id) {
+                                                return;
+                                            }
+                                        }
+                                    }
+
                                     if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
-                                        span_lint_and_then(
+                                        span_lint_hir_and_then(
                                             cx,
-                                            NEW_WITHOUT_DEFAULT_DERIVE,
+                                            NEW_WITHOUT_DEFAULT,
+                                            id,
                                             impl_item.span,
-                                            &format!("you should consider deriving a `Default` implementation for `{}`", self_ty),
+                                            &format!(
+                                                "you should consider deriving a `Default` implementation for `{}`",
+                                                self_ty
+                                            ),
                                             |db| {
-                                                db.suggest_item_with_attr(cx, sp, "try this", "#[derive(Default)]");
+                                                db.suggest_item_with_attr(
+                                                    cx,
+                                                    sp,
+                                                    "try this",
+                                                    "#[derive(Default)]",
+                                                    Applicability::MaybeIncorrect,
+                                                );
                                             });
                                     } else {
-                                        span_lint_and_then(
+                                        span_lint_hir_and_then(
                                             cx,
                                             NEW_WITHOUT_DEFAULT,
+                                            id,
                                             impl_item.span,
-                                            &format!("you should consider adding a `Default` implementation for `{}`", self_ty),
+                                            &format!(
+                                                "you should consider adding a `Default` implementation for `{}`",
+                                                self_ty
+                                            ),
                                             |db| {
                                                 db.suggest_prepend_item(
                                                     cx,
                                                     item.span,
                                                     "try this",
                                                     &create_new_without_default_suggest_msg(self_ty),
+                                                    Applicability::MaybeIncorrect,
                                                 );
                                             },
                                         );
@@ -158,7 +205,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
 }
 
 fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
-    #[cfg_attr(rustfmt, rustfmt_skip)]
+    #[rustfmt::skip]
     format!(
 "impl Default for {} {{
     fn default() -> Self {{
@@ -169,7 +216,7 @@ fn default() -> Self {{
 
 fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
     match ty.sty {
-        ty::TyAdt(adt_def, substs) if adt_def.is_struct() => {
+        ty::Adt(adt_def, substs) if adt_def.is_struct() => {
             for field in adt_def.all_fields() {
                 let f_ty = field.ty(cx.tcx, substs);
                 if !implements_trait(cx, f_ty, default_trait_id, &[]) {
index cacb5d6a9ffcc31d9749b41a7113c9e24e273ade..8c5ddaf4140f7b3fd76e0cf3027637be0ef14824 100644 (file)
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
-use rustc::hir::def::Def;
+use crate::utils::{has_drop, in_macro_or_desugar, 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 crate::utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use std::ops::Deref;
 
-/// **What it does:** Checks for statements which have no effect.
-///
-/// **Why is this bad?** Similar to dead code, these statements are actually
-/// executed. However, as they have no effect, all they do is make the code less
-/// readable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// 0;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for statements which have no effect.
+    ///
+    /// **Why is this bad?** Similar to dead code, these statements are actually
+    /// executed. However, as they have no effect, all they do is make the code less
+    /// readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// 0;
+    /// ```
     pub NO_EFFECT,
     complexity,
     "statements with no effect"
 }
 
-/// **What it does:** Checks for expression statements that can be reduced to a
-/// sub-expression.
-///
-/// **Why is this bad?** Expressions by themselves often have no side-effects.
-/// Having such expressions reduces readability.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// compute_array()[0];
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for expression statements that can be reduced to a
+    /// sub-expression.
+    ///
+    /// **Why is this bad?** Expressions by themselves often have no side-effects.
+    /// Having such expressions reduces readability.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// compute_array()[0];
+    /// ```
     pub UNNECESSARY_OPERATION,
     complexity,
     "outer expressions with no effect"
 }
 
 fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
-    if in_macro(expr.span) {
+    if in_macro_or_desugar(expr.span) {
         return false;
     }
     match expr.node {
         ExprKind::Lit(..) | ExprKind::Closure(.., _) => true,
-        ExprKind::Path(..) => !has_drop(cx, expr),
+        ExprKind::Path(..) => !has_drop(cx, cx.tables.expr_ty(expr)),
         ExprKind::Index(ref a, ref b) | ExprKind::Binary(_, ref a, ref b) => {
             has_no_effect(cx, a) && has_no_effect(cx, b)
         },
         ExprKind::Array(ref v) | ExprKind::Tup(ref v) => v.iter().all(|val| has_no_effect(cx, val)),
-        ExprKind::Repeat(ref inner, _) |
-        ExprKind::Cast(ref inner, _) |
-        ExprKind::Type(ref inner, _) |
-        ExprKind::Unary(_, ref inner) |
-        ExprKind::Field(ref inner, _) |
-        ExprKind::AddrOf(_, ref inner) |
-        ExprKind::Box(ref inner) => has_no_effect(cx, inner),
+        ExprKind::Repeat(ref inner, _)
+        | ExprKind::Cast(ref inner, _)
+        | ExprKind::Type(ref inner, _)
+        | ExprKind::Unary(_, ref inner)
+        | ExprKind::Field(ref inner, _)
+        | ExprKind::AddrOf(_, ref inner)
+        ExprKind::Box(ref inner) => has_no_effect(cx, inner),
         ExprKind::Struct(_, ref fields, ref base) => {
-            !has_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base {
-                Some(ref base) => has_no_effect(cx, base),
-                None => true,
-            }
-        },
-        ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node {
-            let def = cx.tables.qpath_def(qpath, callee.hir_id);
-            match def {
-                Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
-                    !has_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
-                },
-                _ => false,
-            }
-        } else {
-            false
+            !has_drop(cx, cx.tables.expr_ty(expr))
+                && fields.iter().all(|field| has_no_effect(cx, &field.expr))
+                && match *base {
+                    Some(ref base) => has_no_effect(cx, base),
+                    None => true,
+                }
         },
-        ExprKind::Block(ref block, _) => {
-            block.stmts.is_empty() && if let Some(ref expr) = block.expr {
-                has_no_effect(cx, expr)
+        ExprKind::Call(ref callee, ref args) => {
+            if let ExprKind::Path(ref qpath) = callee.node {
+                let res = cx.tables.qpath_res(qpath, callee.hir_id);
+                match res {
+                    Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(..), _) => {
+                        !has_drop(cx, cx.tables.expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
+                    },
+                    _ => false,
+                }
             } else {
                 false
             }
         },
+        ExprKind::Block(ref block, _) => {
+            block.stmts.is_empty()
+                && if let Some(ref expr) = block.expr {
+                    has_no_effect(cx, expr)
+                } else {
+                    false
+                }
+        },
         _ => false,
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
+declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NO_EFFECT, UNNECESSARY_OPERATION)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoEffect {
     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
-        if let StmtKind::Semi(ref expr, _) = stmt.node {
+        if let StmtKind::Semi(ref expr) = stmt.node {
             if has_no_effect(cx, expr) {
                 span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
             } else if let Some(reduced) = reduce_expression(cx, expr) {
                 let mut snippet = String::new();
                 for e in reduced {
-                    if in_macro(e.span) {
+                    if in_macro_or_desugar(e.span) {
                         return;
                     }
                     if let Some(snip) = snippet_opt(cx, e.span) {
@@ -121,15 +120,15 @@ fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
                     "statement can be reduced",
                     "replace it with",
                     snippet,
+                    Applicability::MachineApplicable,
                 );
             }
         }
     }
 }
 
-
 fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec<&'a Expr>> {
-    if in_macro(expr.span) {
+    if in_macro_or_desugar(expr.span) {
         return None;
     }
     match expr.node {
@@ -138,37 +137,34 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec
             Some(vec![&**a, &**b])
         },
         ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()),
-        ExprKind::Repeat(ref inner, _) |
-        ExprKind::Cast(ref inner, _) |
-        ExprKind::Type(ref inner, _) |
-        ExprKind::Unary(_, ref inner) |
-        ExprKind::Field(ref inner, _) |
-        ExprKind::AddrOf(_, ref inner) |
-        ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
-        ExprKind::Struct(_, ref fields, ref base) => if has_drop(cx, expr) {
-            None
-        } else {
-            Some(
-                fields
-                    .iter()
-                    .map(|f| &f.expr)
-                    .chain(base)
-                    .map(Deref::deref)
-                    .collect(),
-            )
+        ExprKind::Repeat(ref inner, _)
+        | ExprKind::Cast(ref inner, _)
+        | ExprKind::Type(ref inner, _)
+        | ExprKind::Unary(_, ref inner)
+        | ExprKind::Field(ref inner, _)
+        | ExprKind::AddrOf(_, ref inner)
+        | ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
+        ExprKind::Struct(_, ref fields, ref base) => {
+            if has_drop(cx, cx.tables.expr_ty(expr)) {
+                None
+            } else {
+                Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
+            }
         },
-        ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node {
-            let def = cx.tables.qpath_def(qpath, callee.hir_id);
-            match def {
-                Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
-                    if !has_drop(cx, expr) =>
-                {
-                    Some(args.iter().collect())
-                },
-                _ => None,
+        ExprKind::Call(ref callee, ref args) => {
+            if let ExprKind::Path(ref qpath) = callee.node {
+                let res = cx.tables.qpath_res(qpath, callee.hir_id);
+                match res {
+                    Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(..), _)
+                        if !has_drop(cx, cx.tables.expr_ty(expr)) =>
+                    {
+                        Some(args.iter().collect())
+                    },
+                    _ => None,
+                }
+            } else {
+                None
             }
-        } else {
-            None
         },
         ExprKind::Block(ref block, _) => {
             if block.stmts.is_empty() {
index f2c9210aae4e0d42dd53d5c4612c46e8273ac69c..2d56b4ee8b4e1ab6ac4a85da2a03f4823401a687 100644 (file)
@@ -1,82 +1,84 @@
-//! Checks for uses of const which the type is not Freeze (Cell-free).
+//! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
 //!
 //! This lint is **deny** by default.
 
-use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
+use std::ptr;
+
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::*;
-use rustc::hir::def::Def;
-use rustc::ty::{self, TypeFlags};
+use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
 use rustc::ty::adjustment::Adjust;
+use rustc::ty::{Ty, TypeFlags};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use rustc_errors::Applicability;
 use rustc_typeck::hir_ty_to_ty;
-use syntax_pos::{DUMMY_SP, Span};
-use std::ptr;
-use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then};
+use syntax_pos::{Span, DUMMY_SP};
+
+use crate::utils::{in_constant, in_macro_or_desugar, is_copy, span_lint_and_then};
 
-/// **What it does:** Checks for declaration of `const` items which is interior
-/// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc).
-///
-/// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.
-/// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
-/// or `AtomicXxxx` will be created, which defeats the whole purpose of using
-/// these types in the first place.
-///
-/// The `const` should better be replaced by a `static` item if a global
-/// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
-///
-/// **Known problems:** A "non-constant" const item is a legacy way to supply an
-/// initialized value to downstream `static` items (e.g. the
-/// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
-/// and this lint should be suppressed.
-///
-/// **Example:**
-/// ```rust
-/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize};
-///
-/// // Bad.
-/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
-/// CONST_ATOM.store(6, SeqCst);             // the content of the atomic is unchanged
-/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
-///
-/// // Good.
-/// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
-/// STATIC_ATOM.store(9, SeqCst);
-/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for declaration of `const` items which is interior
+    /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
+    ///
+    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
+    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
+    /// these types in the first place.
+    ///
+    /// The `const` should better be replaced by a `static` item if a global
+    /// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
+    ///
+    /// **Known problems:** A "non-constant" const item is a legacy way to supply an
+    /// initialized value to downstream `static` items (e.g., the
+    /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
+    /// and this lint should be suppressed.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+    ///
+    /// // Bad.
+    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+    ///
+    /// // Good.
+    /// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
+    /// STATIC_ATOM.store(9, SeqCst);
+    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+    /// ```
     pub DECLARE_INTERIOR_MUTABLE_CONST,
     correctness,
     "declaring const with interior mutability"
 }
 
-/// **What it does:** Checks if `const` items which is interior mutable (e.g.
-/// contains a `Cell`, `Mutex`, `AtomicXxxx` etc) has been borrowed directly.
-///
-/// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.
-/// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
-/// or `AtomicXxxx` will be created, which defeats the whole purpose of using
-/// these types in the first place.
-///
-/// The `const` value should be stored inside a `static` item.
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize};
-/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
-///
-/// // Bad.
-/// CONST_ATOM.store(6, SeqCst);             // the content of the atomic is unchanged
-/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
-///
-/// // Good.
-/// static STATIC_ATOM: AtomicUsize = CONST_ATOM;
-/// STATIC_ATOM.store(9, SeqCst);
-/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks if `const` items which is interior mutable (e.g.,
+    /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
+    ///
+    /// **Why is this bad?** Consts are copied everywhere they are referenced, i.e.,
+    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
+    /// these types in the first place.
+    ///
+    /// The `const` value should be stored inside a `static` item.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+    /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+    ///
+    /// // Bad.
+    /// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+    /// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+    ///
+    /// // Good.
+    /// static STATIC_ATOM: AtomicUsize = CONST_ATOM;
+    /// STATIC_ATOM.store(9, SeqCst);
+    /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+    /// ```
     pub BORROW_INTERIOR_MUTABLE_CONST,
     correctness,
     "referencing const with interior mutability"
 
 #[derive(Copy, Clone)]
 enum Source {
-    Item {
-        item: Span,
-    },
-    Assoc {
-        item: Span,
-        ty: Span,
-    },
-    Expr {
-        expr: Span,
-    },
+    Item { item: Span },
+    Assoc { item: Span, ty: Span },
+    Expr { expr: Span },
 }
 
 impl Source {
@@ -113,55 +108,42 @@ fn lint(&self) -> (&'static Lint, &'static str, Span) {
     }
 }
 
-fn verify_ty_bound<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    ty: ty::Ty<'tcx>,
-    source: Source,
-) {
+fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>, source: Source) {
     if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) {
-        // an UnsafeCell is !Copy, and an UnsafeCell is also the only type which
-        // is !Freeze, thus if our type is Copy we can be sure it must be Freeze
+        // An `UnsafeCell` is `!Copy`, and an `UnsafeCell` is also the only type which
+        // is `!Freeze`, thus if our type is `Copy` we can be sure it must be `Freeze`
         // as well.
         return;
     }
 
     let (lint, msg, span) = source.lint();
     span_lint_and_then(cx, lint, span, msg, |db| {
-        if in_macro(span) {
+        if in_macro_or_desugar(span) {
             return; // Don't give suggestions into macros.
         }
         match source {
             Source::Item { .. } => {
                 let const_kw_span = span.from_inner_byte_pos(0, 5);
-                db.span_suggestion_with_applicability(
+                db.span_suggestion(
                     const_kw_span,
                     "make this a static item",
                     "static".to_string(),
                     Applicability::MachineApplicable,
                 );
-            }
+            },
             Source::Assoc { ty: ty_span, .. } => {
                 if ty.flags.contains(TypeFlags::HAS_FREE_LOCAL_NAMES) {
                     db.span_help(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
                 }
-            }
+            },
             Source::Expr { .. } => {
-                db.help(
-                    "assign this const to a local or static variable, and use the variable here",
-                );
-            }
+                db.help("assign this const to a local or static variable, and use the variable here");
+            },
         }
     });
 }
 
-
-pub struct NonCopyConst;
-
-impl LintPass for NonCopyConst {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST)
-    }
-}
+declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx Item) {
@@ -174,18 +156,32 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx Item) {
     fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx TraitItem) {
         if let TraitItemKind::Const(hir_ty, ..) = &trait_item.node {
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-            verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: trait_item.span });
+            verify_ty_bound(
+                cx,
+                ty,
+                Source::Assoc {
+                    ty: hir_ty.span,
+                    item: trait_item.span,
+                },
+            );
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplItem) {
         if let ImplItemKind::Const(hir_ty, ..) = &impl_item.node {
-            let item_node_id = cx.tcx.hir.get_parent_node(impl_item.id);
-            let item = cx.tcx.hir.expect_item(item_node_id);
-            // ensure the impl is an inherent impl.
+            let item_hir_id = cx.tcx.hir().get_parent_node_by_hir_id(impl_item.hir_id);
+            let item = cx.tcx.hir().expect_item_by_hir_id(item_hir_id);
+            // Ensure the impl is an inherent impl.
             if let ItemKind::Impl(_, _, _, _, None, _, _) = item.node {
                 let ty = hir_ty_to_ty(cx.tcx, hir_ty);
-                verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: impl_item.span });
+                verify_ty_bound(
+                    cx,
+                    ty,
+                    Source::Assoc {
+                        ty: hir_ty.span,
+                        item: impl_item.span,
+                    },
+                );
             }
         }
     }
@@ -193,49 +189,49 @@ fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplI
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::Path(qpath) = &expr.node {
             // Only lint if we use the const item inside a function.
-            if in_constant(cx, expr.id) {
+            if in_constant(cx, expr.hir_id) {
                 return;
             }
 
-            // make sure it is a const item.
-            match cx.tables.qpath_def(qpath, expr.hir_id) {
-                Def::Const(_) | Def::AssociatedConst(_) => {},
+            // Make sure it is a const item.
+            match cx.tables.qpath_res(qpath, expr.hir_id) {
+                Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssociatedConst, _) => {},
                 _ => return,
             };
 
-            // climb up to resolve any field access and explicit referencing.
+            // Climb up to resolve any field access and explicit referencing.
             let mut cur_expr = expr;
             let mut dereferenced_expr = expr;
             let mut needs_check_adjustment = true;
             loop {
-                let parent_id = cx.tcx.hir.get_parent_node(cur_expr.id);
-                if parent_id == cur_expr.id {
+                let parent_id = cx.tcx.hir().get_parent_node_by_hir_id(cur_expr.hir_id);
+                if parent_id == cur_expr.hir_id {
                     break;
                 }
-                if let Some(map::NodeExpr(parent_expr)) = cx.tcx.hir.find(parent_id) {
+                if let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find_by_hir_id(parent_id) {
                     match &parent_expr.node {
                         ExprKind::AddrOf(..) => {
-                            // `&e` => `e` must be referenced
+                            // `&e` => `e` must be referenced.
                             needs_check_adjustment = false;
-                        }
+                        },
                         ExprKind::Field(..) => {
                             dereferenced_expr = parent_expr;
                             needs_check_adjustment = true;
-                        }
+                        },
                         ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
                             // `e[i]` => desugared to `*Index::index(&e, i)`,
                             // meaning `e` must be referenced.
                             // no need to go further up since a method call is involved now.
                             needs_check_adjustment = false;
                             break;
-                        }
+                        },
                         ExprKind::Unary(UnDeref, _) => {
                             // `*e` => desugared to `*Deref::deref(&e)`,
                             // meaning `e` must be referenced.
                             // no need to go further up since a method call is involved now.
                             needs_check_adjustment = false;
                             break;
-                        }
+                        },
                         _ => break,
                     }
                     cur_expr = parent_expr;
@@ -244,9 +240,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 }
             }
 
-            let ty = if !needs_check_adjustment {
-                cx.tables.expr_ty(dereferenced_expr)
-            } else {
+            let ty = if needs_check_adjustment {
                 let adjustments = cx.tables.expr_adjustments(dereferenced_expr);
                 if let Some(i) = adjustments.iter().position(|adj| match adj.kind {
                     Adjust::Borrow(_) | Adjust::Deref(_) => true,
@@ -258,9 +252,11 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                         adjustments[i - 1].target
                     }
                 } else {
-                    // No borrow adjustments = the entire const is moved.
+                    // No borrow adjustments means the entire const is moved.
                     return;
                 }
+            } else {
+                cx.tables.expr_ty(dereferenced_expr)
             };
 
             verify_ty_bound(cx, ty, Source::Expr { expr: expr.span });
index e9688262c2a76eeb401771d58c3de37cdec41f35..12976e05b087eced7f588b1b02d9d07c03c6d67f 100644 (file)
@@ -1,77 +1,75 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::codemap::Span;
-use syntax::symbol::LocalInternedString;
+use crate::utils::sym;
+use crate::utils::{span_lint, span_lint_and_then};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
 use syntax::ast::*;
 use syntax::attr;
+use syntax::source_map::Span;
+use syntax::symbol::LocalInternedString;
 use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor};
-use crate::utils::{in_macro, span_lint, span_lint_and_then};
 
-/// **What it does:** Checks for names that are very similar and thus confusing.
-///
-/// **Why is this bad?** It's hard to distinguish between names that differ only
-/// by a single character.
-///
-/// **Known problems:** None?
-///
-/// **Example:**
-/// ```rust
-/// let checked_exp = something;
-/// let checked_expr = something_else;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for names that are very similar and thus confusing.
+    ///
+    /// **Why is this bad?** It's hard to distinguish between names that differ only
+    /// by a single character.
+    ///
+    /// **Known problems:** None?
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let checked_exp = something;
+    /// let checked_expr = something_else;
+    /// ```
     pub SIMILAR_NAMES,
     pedantic,
     "similarly named items and bindings"
 }
 
-/// **What it does:** Checks for too many variables whose name consists of a
-/// single character.
-///
-/// **Why is this bad?** It's hard to memorize what a variable means without a
-/// descriptive name.
-///
-/// **Known problems:** None?
-///
-/// **Example:**
-/// ```rust
-/// let (a, b, c, d, e, f, g) = (...);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for too many variables whose name consists of a
+    /// single character.
+    ///
+    /// **Why is this bad?** It's hard to memorize what a variable means without a
+    /// descriptive name.
+    ///
+    /// **Known problems:** None?
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let (a, b, c, d, e, f, g) = (...);
+    /// ```
     pub MANY_SINGLE_CHAR_NAMES,
     style,
     "too many single character bindings"
 }
 
-/// **What it does:** Checks if you have variables whose name consists of just
-/// underscores and digits.
-///
-/// **Why is this bad?** It's hard to memorize what a variable means without a
-/// descriptive name.
-///
-/// **Known problems:** None?
-///
-/// **Example:**
-/// ```rust
-/// let _1 = 1;
-/// let ___1 = 1;
-/// let __1___2 = 11;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks if you have variables whose name consists of just
+    /// underscores and digits.
+    ///
+    /// **Why is this bad?** It's hard to memorize what a variable means without a
+    /// descriptive name.
+    ///
+    /// **Known problems:** None?
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _1 = 1;
+    /// let ___1 = 1;
+    /// let __1___2 = 11;
+    /// ```
     pub JUST_UNDERSCORES_AND_DIGITS,
     style,
     "unclear name"
 }
 
+#[derive(Copy, Clone)]
 pub struct NonExpressiveNames {
     pub single_char_binding_names_threshold: u64,
 }
 
-impl LintPass for NonExpressiveNames {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS)
-    }
-}
+impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);
 
 struct ExistingName {
     interned: LocalInternedString,
@@ -84,12 +82,38 @@ struct SimilarNamesLocalVisitor<'a, 'tcx: 'a> {
     names: Vec<ExistingName>,
     cx: &'a EarlyContext<'tcx>,
     lint: &'a NonExpressiveNames,
-    single_char_names: Vec<char>,
+
+    /// A stack of scopes containing the single-character bindings in each scope.
+    single_char_names: Vec<Vec<Ident>>,
+}
+
+impl<'a, 'tcx: 'a> SimilarNamesLocalVisitor<'a, 'tcx> {
+    fn check_single_char_names(&self) {
+        let num_single_char_names = self.single_char_names.iter().flatten().count();
+        let threshold = self.lint.single_char_binding_names_threshold;
+        if num_single_char_names as u64 >= threshold {
+            let span = self
+                .single_char_names
+                .iter()
+                .flatten()
+                .map(|ident| ident.span)
+                .collect::<Vec<_>>();
+            span_lint(
+                self.cx,
+                MANY_SINGLE_CHAR_NAMES,
+                span,
+                &format!(
+                    "{} bindings with single-character names in scope",
+                    num_single_char_names
+                ),
+            );
+        }
+    }
 }
 
 // this list contains lists of names that are allowed to be similar
 // the assumption is that no name is ever contained in multiple lists.
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 const WHITELIST: &[&[&str]] = &[
     &["parsed", "parser"],
     &["lhs", "rhs"],
@@ -105,15 +129,20 @@ struct SimilarNamesLocalVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
     fn visit_pat(&mut self, pat: &'tcx Pat) {
         match pat.node {
-            PatKind::Ident(_, ident, _) => self.check_name(ident.span, ident.name),
-            PatKind::Struct(_, ref fields, _) => for field in fields {
-                if !field.node.is_shorthand {
-                    self.visit_pat(&field.node.pat);
+            PatKind::Ident(_, ident, _) => self.check_ident(ident),
+            PatKind::Struct(_, ref fields, _) => {
+                for field in fields {
+                    if !field.node.is_shorthand {
+                        self.visit_pat(&field.node.pat);
+                    }
                 }
             },
             _ => walk_pat(self, pat),
         }
     }
+    fn visit_mac(&mut self, _mac: &Mac) {
+        // do not check macs
+    }
 }
 
 fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
@@ -131,26 +160,24 @@ fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
 }
 
 impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
-    fn check_short_name(&mut self, c: char, span: Span) {
-        // make sure we ignore shadowing
-        if self.0.single_char_names.contains(&c) {
+    fn check_short_ident(&mut self, ident: Ident) {
+        // Ignore shadowing
+        if self
+            .0
+            .single_char_names
+            .iter()
+            .flatten()
+            .any(|id| id.name == ident.name)
+        {
             return;
-        }
-        self.0.single_char_names.push(c);
-        if self.0.single_char_names.len() as u64 >= self.0.lint.single_char_binding_names_threshold {
-            span_lint(
-                self.0.cx,
-                MANY_SINGLE_CHAR_NAMES,
-                span,
-                &format!("{}th binding whose name is just one char", self.0.single_char_names.len()),
-            );
+        } else if let Some(scope) = &mut self.0.single_char_names.last_mut() {
+            scope.push(ident);
         }
     }
-    fn check_name(&mut self, span: Span, name: Name) {
-        if in_macro(span) {
-            return;
-        }
-        let interned_name = name.as_str();
+
+    #[allow(clippy::too_many_lines)]
+    fn check_ident(&mut self, ident: Ident) {
+        let interned_name = ident.name.as_str();
         if interned_name.chars().any(char::is_uppercase) {
             return;
         }
@@ -158,7 +185,7 @@ fn check_name(&mut self, span: Span, name: Name) {
             span_lint(
                 self.0.cx,
                 JUST_UNDERSCORES_AND_DIGITS,
-                span,
+                ident.span,
                 "consider choosing a more descriptive name",
             );
             return;
@@ -166,8 +193,7 @@ fn check_name(&mut self, span: Span, name: Name) {
         let count = interned_name.chars().count();
         if count < 3 {
             if count == 1 {
-                let c = interned_name.chars().next().expect("already checked");
-                self.check_short_name(c, span);
+                self.check_short_ident(ident);
             }
             return;
         }
@@ -187,26 +213,19 @@ fn check_name(&mut self, span: Span, name: Name) {
             } else {
                 let mut interned_chars = interned_name.chars();
                 let mut existing_chars = existing_name.interned.chars();
-                let first_i = interned_chars
-                    .next()
-                    .expect("we know we have at least one char");
-                let first_e = existing_chars
-                    .next()
-                    .expect("we know we have at least one char");
+                let first_i = interned_chars.next().expect("we know we have at least one char");
+                let first_e = existing_chars.next().expect("we know we have at least one char");
                 let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();
 
                 if eq_or_numeric((first_i, first_e)) {
-                    let last_i = interned_chars
-                        .next_back()
-                        .expect("we know we have at least two chars");
-                    let last_e = existing_chars
-                        .next_back()
-                        .expect("we know we have at least two chars");
+                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
+                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                     if eq_or_numeric((last_i, last_e)) {
                         if interned_chars
                             .zip(existing_chars)
                             .filter(|&ie| !eq_or_numeric(ie))
-                            .count() != 1
+                            .count()
+                            != 1
                         {
                             continue;
                         }
@@ -217,7 +236,8 @@ fn check_name(&mut self, span: Span, name: Name) {
                         let second_last_e = existing_chars
                             .next_back()
                             .expect("we know we have at least three chars");
-                        if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_'
+                        if !eq_or_numeric((second_last_i, second_last_e))
+                            || second_last_i == '_'
                             || !interned_chars.zip(existing_chars).all(eq_or_numeric)
                         {
                             // allowed similarity foo_x, foo_y
@@ -227,32 +247,29 @@ fn check_name(&mut self, span: Span, name: Name) {
                         split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                     }
                 } else {
-                    let second_i = interned_chars
-                        .next()
-                        .expect("we know we have at least two chars");
-                    let second_e = existing_chars
-                        .next()
-                        .expect("we know we have at least two chars");
-                    if !eq_or_numeric((second_i, second_e)) || second_i == '_'
+                    let second_i = interned_chars.next().expect("we know we have at least two chars");
+                    let second_e = existing_chars.next().expect("we know we have at least two chars");
+                    if !eq_or_numeric((second_i, second_e))
+                        || second_i == '_'
                         || !interned_chars.zip(existing_chars).all(eq_or_numeric)
                     {
                         // allowed similarity x_foo, y_foo
                         // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                         continue;
                     }
-                    split_at = interned_name.chars().next().map(|c| c.len_utf8());
+                    split_at = interned_name.chars().next().map(char::len_utf8);
                 }
             }
             span_lint_and_then(
                 self.0.cx,
                 SIMILAR_NAMES,
-                span,
+                ident.span,
                 "binding's name is too similar to existing binding",
                 |diag| {
                     diag.span_note(existing_name.span, "existing binding defined here");
                     if let Some(split) = split_at {
                         diag.span_help(
-                            span,
+                            ident.span,
                             &format!(
                                 "separate the discriminating character by an \
                                  underscore like: `{}_{}`",
@@ -268,7 +285,7 @@ fn check_name(&mut self, span: Span, name: Name) {
         self.0.names.push(ExistingName {
             whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
             interned: interned_name,
-            span,
+            span: ident.span,
             len: count,
         });
     }
@@ -296,19 +313,32 @@ fn visit_local(&mut self, local: &'tcx Local) {
         SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
     }
     fn visit_block(&mut self, blk: &'tcx Block) {
+        self.single_char_names.push(vec![]);
+
         self.apply(|this| walk_block(this, blk));
+
+        self.check_single_char_names();
+        self.single_char_names.pop();
     }
     fn visit_arm(&mut self, arm: &'tcx Arm) {
+        self.single_char_names.push(vec![]);
+
         self.apply(|this| {
             // just go through the first pattern, as either all patterns
             // bind the same bindings or rustc would have errored much earlier
             SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);
             this.apply(|this| walk_expr(this, &arm.body));
         });
+
+        self.check_single_char_names();
+        self.single_char_names.pop();
     }
     fn visit_item(&mut self, _: &Item) {
         // do not recurse into inner items
     }
+    fn visit_mac(&mut self, _mac: &Mac) {
+        // do not check macs
+    }
 }
 
 impl EarlyLintPass for NonExpressiveNames {
@@ -323,23 +353,25 @@ fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &ImplItem) {
             do_check(self, cx, &item.attrs, &sig.decl, blk);
         }
     }
-
 }
 
 fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
-    if !attr::contains_name(attrs, "test") {
+    if !attr::contains_name(attrs, *sym::test) {
         let mut visitor = SimilarNamesLocalVisitor {
             names: Vec::new(),
             cx,
             lint,
-            single_char_names: Vec::new(),
+            single_char_names: vec![vec![]],
         };
+
         // initialize with function arguments
         for arg in &decl.inputs {
             SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat);
         }
         // walk all other bindings
         walk_block(&mut visitor, blk);
+
+        visitor.check_single_char_names();
     }
 }
 
index 2a7f71c714521cfe721a31057e854c67ebd84e57..c097f17d30e29776c427f143a2c5a624f00c4b32 100644 (file)
@@ -1,59 +1,53 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint};
 use if_chain::if_chain;
 use rustc::hir::*;
-use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:*** Checks for unnecessary `ok()` in if let.
-///
-/// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match
-/// on `Ok(pat)`
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for result in iter {
-///     if let Some(bench) = try!(result).parse().ok() {
-///         vec.push(bench)
-///     }
-/// }
-/// ```
-/// Could be written:
-///
-/// ```rust
-/// for result in iter {
-///     if let Ok(bench) = try!(result).parse() {
-///         vec.push(bench)
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:*** Checks for unnecessary `ok()` in if let.
+    ///
+    /// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match
+    /// on `Ok(pat)`
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for result in iter {
+    ///     if let Some(bench) = try!(result).parse().ok() {
+    ///         vec.push(bench)
+    ///     }
+    /// }
+    /// ```
+    /// Could be written:
+    ///
+    /// ```ignore
+    /// for result in iter {
+    ///     if let Ok(bench) = try!(result).parse() {
+    ///         vec.push(bench)
+    ///     }
+    /// }
+    /// ```
     pub IF_LET_SOME_RESULT,
     style,
     "usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(IF_LET_SOME_RESULT)
-    }
-}
+declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! { //begin checking variables
             if let ExprKind::Match(ref op, ref body, ref source) = expr.node; //test if expr is a match
             if let MatchSource::IfLetDesugar { .. } = *source; //test if it is an If Let
             if let ExprKind::MethodCall(_, _, ref result_types) = op.node; //check is expr.ok() has type Result<T,E>.ok()
             if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = body[0].pats[0].node; //get operation
-            if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
+            if method_chain_args(op, &[*sym::ok]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
 
             then {
-                let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
+                let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &*paths::RESULT);
                 let some_expr_string = snippet(cx, y[0].span, "");
                 if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type {
                     span_help_and_lint(cx, IF_LET_SOME_RESULT, expr.span,
index effeb88d0cf8569d8457067c23846c21d460641f..fa3e589d92b75b5049fad18633699d5366c74f89 100644 (file)
@@ -1,42 +1,38 @@
+use crate::utils::sym;
+use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty};
 use rustc::hir::{Expr, ExprKind};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::LitKind;
-use syntax::codemap::{Span, Spanned};
-use crate::utils::{match_type, paths, span_lint, walk_ptrs_ty};
+use syntax::source_map::{Span, Spanned};
 
-/// **What it does:** Checks for duplicate open options as well as combinations
-/// that make no sense.
-///
-/// **Why is this bad?** In the best case, the code will be harder to read than
-/// necessary. I don't know the worst case.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// OpenOptions::new().read(true).truncate(true)
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for duplicate open options as well as combinations
+    /// that make no sense.
+    ///
+    /// **Why is this bad?** In the best case, the code will be harder to read than
+    /// necessary. I don't know the worst case.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::fs::OpenOptions;
+    ///
+    /// OpenOptions::new().read(true).truncate(true);
+    /// ```
     pub NONSENSICAL_OPEN_OPTIONS,
     correctness,
     "nonsensical combination of options for opening a file"
 }
 
-#[derive(Copy, Clone)]
-pub struct NonSensical;
-
-impl LintPass for NonSensical {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NONSENSICAL_OPEN_OPTIONS)
-    }
-}
+declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSensical {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
         if let ExprKind::MethodCall(ref path, _, ref arguments) = e.node {
             let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0]));
-            if path.ident.name == "open" && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
+            if path.ident.name == *sym::open && match_type(cx, obj_ty, &*paths::OPEN_OPTIONS) {
                 let mut options = Vec::new();
                 get_open_options(cx, &arguments[0], &mut options);
                 check_open_options(cx, &options, e.span);
@@ -66,13 +62,13 @@ fn get_open_options(cx: &LateContext<'_, '_>, argument: &Expr, options: &mut Vec
         let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&arguments[0]));
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
-        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
+        if match_type(cx, obj_ty, &*paths::OPEN_OPTIONS) && arguments.len() >= 2 {
             let argument_option = match arguments[1].node {
                 ExprKind::Lit(ref span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
                         ..
-                    } = **span
+                    } = *span
                     {
                         if lit {
                             Argument::True
@@ -190,7 +186,12 @@ fn check_open_options(cx: &LateContext<'_, '_>, options: &[(OpenOption, Argument
     }
 
     if read && truncate && read_arg && truncate_arg && !(write && write_arg) {
-        span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\"");
+        span_lint(
+            cx,
+            NONSENSICAL_OPEN_OPTIONS,
+            span,
+            "file opened with \"truncate\" and \"read\"",
+        );
     }
     if append && truncate && append_arg && truncate_arg {
         span_lint(
index 5714bdb521c83f4df32eab7f415e4af32ae2bcdb..c598e915a5af5a55ae9ccae4dd36dce0e4abf305 100644 (file)
@@ -1,34 +1,27 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{span_lint, SpanlessEq};
 use if_chain::if_chain;
 use rustc::hir::*;
-use crate::utils::{span_lint, SpanlessEq};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Detects classic underflow/overflow checks.
-///
-/// **Why is this bad?** Most classic C underflow/overflow checks will fail in
-/// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// a + b < a
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects classic underflow/overflow checks.
+    ///
+    /// **Why is this bad?** Most classic C underflow/overflow checks will fail in
+    /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// a + b < a
+    /// ```
     pub OVERFLOW_CHECK_CONDITIONAL,
     complexity,
     "overflow checks inspired by C which are likely to panic"
 }
 
-#[derive(Copy, Clone)]
-pub struct OverflowCheckConditional;
-
-impl LintPass for OverflowCheckConditional {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(OVERFLOW_CHECK_CONDITIONAL)
-    }
-}
+declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OverflowCheckConditional {
     // a + b < a, a > a + b, a < a - b, a - b > a
index e603773f7ba40155529303f9c362c5a24f2351a5..8f896acbd3d3dd41c341ec616826b6c44af9dd05 100644 (file)
@@ -1,68 +1,62 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, paths, resolve_node, span_lint};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::LitKind;
 use syntax::ptr::P;
-use syntax::ext::quote::rt::Span;
-use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint};
+use syntax_pos::Span;
 
-/// **What it does:** Checks for missing parameters in `panic!`.
-///
-/// **Why is this bad?** Contrary to the `format!` family of macros, there are
-/// two forms of `panic!`: if there are no parameters given, the first argument
-/// is not a format string and used literally. So while `format!("{}")` will
-/// fail to compile, `panic!("{}")` will not.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// panic!("This `panic!` is probably missing a parameter there: {}");
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for missing parameters in `panic!`.
+    ///
+    /// **Why is this bad?** Contrary to the `format!` family of macros, there are
+    /// two forms of `panic!`: if there are no parameters given, the first argument
+    /// is not a format string and used literally. So while `format!("{}")` will
+    /// fail to compile, `panic!("{}")` will not.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```no_run
+    /// panic!("This `panic!` is probably missing a parameter there: {}");
+    /// ```
     pub PANIC_PARAMS,
     style,
     "missing parameters in `panic!` calls"
 }
 
-/// **What it does:** Checks for usage of `unimplemented!`.
-///
-/// **Why is this bad?** This macro should not be present in production code
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// unimplemented!();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `unimplemented!`.
+    ///
+    /// **Why is this bad?** This macro should not be present in production code
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```no_run
+    /// unimplemented!();
+    /// ```
     pub UNIMPLEMENTED,
     restriction,
     "`unimplemented!` should not be present in production code"
 }
 
-#[allow(missing_copy_implementations)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(PANIC_PARAMS, UNIMPLEMENTED)
-    }
-}
+declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
             if let ExprKind::Block(ref block, _) = expr.node;
             if let Some(ref ex) = block.expr;
             if let ExprKind::Call(ref fun, ref params) = ex.node;
             if let ExprKind::Path(ref qpath) = fun.node;
-            if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
-            if match_def_path(cx.tcx, fun_def_id, &paths::BEGIN_PANIC);
+            if let Some(fun_def_id) = resolve_node(cx, qpath, fun.hir_id).opt_def_id();
+            if match_def_path(cx, fun_def_id, &*paths::BEGIN_PANIC);
             if params.len() == 2;
             then {
-                if is_expn_of(expr.span, "unimplemented").is_some() {
+                if is_expn_of(expr.span, *sym::unimplemented).is_some() {
                     let span = get_outer_span(expr);
                     span_lint(cx, UNIMPLEMENTED, span,
                               "`unimplemented` should not be present in production code");
@@ -89,7 +83,7 @@ fn get_outer_span(expr: &Expr) -> Span {
 fn match_panic(params: &P<[Expr]>, expr: &Expr, cx: &LateContext<'_, '_>) {
     if_chain! {
         if let ExprKind::Lit(ref lit) = params[0].node;
-        if is_direct_expn_of(expr.span, "panic").is_some();
+        if is_direct_expn_of(expr.span, *sym::panic).is_some();
         if let LitKind::Str(ref string, _) = lit.node;
         let string = string.as_str().replace("{{", "").replace("}}", "");
         if let Some(par) = string.find('{');
index 675d014c527a09219b2c1c1ddb89e51207b5ef7d..3e146a72ab86bbecfdfdf7956cc67f406bd3d7b4 100644 (file)
@@ -1,56 +1,53 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{is_automatically_derived, span_lint_hir};
 use if_chain::if_chain;
 use rustc::hir::*;
-use crate::utils::{is_automatically_derived, span_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
-///
-/// **Why is this bad?** `PartialEq::ne` is required to always return the
-/// negated result of `PartialEq::eq`, which is exactly what the default
-/// implementation does. Therefore, there should never be any need to
-/// re-implement it.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct Foo;
-///
-/// impl PartialEq for Foo {
-///    fn eq(&self, other: &Foo) -> bool { ... }
-///    fn ne(&self, other: &Foo) -> bool { !(self == other) }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
+    ///
+    /// **Why is this bad?** `PartialEq::ne` is required to always return the
+    /// negated result of `PartialEq::eq`, which is exactly what the default
+    /// implementation does. Therefore, there should never be any need to
+    /// re-implement it.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct Foo;
+    ///
+    /// impl PartialEq for Foo {
+    ///    fn eq(&self, other: &Foo) -> bool { ... }
+    ///    fn ne(&self, other: &Foo) -> bool { !(self == other) }
+    /// }
+    /// ```
     pub PARTIALEQ_NE_IMPL,
     complexity,
     "re-implementing `PartialEq::ne`"
 }
 
-#[derive(Clone, Copy)]
-pub struct Pass;
+declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(PARTIALEQ_NE_IMPL)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PartialEqNeImpl {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if_chain! {
             if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, ref impl_items) = item.node;
             if !is_automatically_derived(&*item.attrs);
             if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
-            if trait_ref.path.def.def_id() == eq_trait;
+            if trait_ref.path.res.def_id() == eq_trait;
             then {
                 for impl_item in impl_items {
-                    if impl_item.ident.name == "ne" {
-                        span_lint(cx,
-                                  PARTIALEQ_NE_IMPL,
-                                  impl_item.span,
-                                  "re-implementing `PartialEq::ne` is unnecessary")
+                    if impl_item.ident.name == *sym::ne {
+                        span_lint_hir(
+                            cx,
+                            PARTIALEQ_NE_IMPL,
+                            impl_item.id.hir_id,
+                            impl_item.span,
+                            "re-implementing `PartialEq::ne` is unnecessary",
+                        );
                     }
                 }
             }
diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs
new file mode 100644 (file)
index 0000000..3234c81
--- /dev/null
@@ -0,0 +1,72 @@
+use crate::utils::sym;
+use crate::utils::{match_type, paths, span_lint_and_sugg, walk_ptrs_ty};
+use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use std::path::{Component, Path};
+use syntax::ast::LitKind;
+
+declare_clippy_lint! {
+    /// **What it does:*** Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
+    /// calls on `PathBuf` that can cause overwrites.
+    ///
+    /// **Why is this bad?** Calling `push` with a root path at the start can overwrite the
+    /// previous defined path.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// use std::path::PathBuf;
+    ///
+    /// let mut x = PathBuf::from("/foo");
+    /// x.push("/bar");
+    /// assert_eq!(x, PathBuf::from("/bar"));
+    /// ```
+    /// Could be written:
+    ///
+    /// ```rust
+    /// use std::path::PathBuf;
+    ///
+    /// let mut x = PathBuf::from("/foo");
+    /// x.push("bar");
+    /// assert_eq!(x, PathBuf::from("/foo/bar"));
+    /// ```
+    pub PATH_BUF_PUSH_OVERWRITE,
+    nursery,
+    "calling `push` with file system root on `PathBuf` can overwrite it"
+}
+
+declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathBufPushOverwrite {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if_chain! {
+            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
+            if path.ident.name == *sym::push;
+            if args.len() == 2;
+            if match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(&args[0])), &*paths::PATH_BUF);
+            if let Some(get_index_arg) = args.get(1);
+            if let ExprKind::Lit(ref lit) = get_index_arg.node;
+            if let LitKind::Str(ref path_lit, _) = lit.node;
+            if let pushed_path = Path::new(&path_lit.as_str());
+            if let Some(pushed_path_lit) = pushed_path.to_str();
+            if pushed_path.has_root();
+            if let Some(root) = pushed_path.components().next();
+            if root == Component::RootDir;
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    PATH_BUF_PUSH_OVERWRITE,
+                    lit.span,
+                    "Calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
+                    "try",
+                    format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
index 6a0f4f147b727b496f0d6b47a84a66b2330d685d..c52b59653706bcf9a1d12524775ad791ca0e32f5 100644 (file)
@@ -1,49 +1,43 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{in_macro_or_desugar, 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;
 use syntax::ast::*;
-use syntax::codemap::Spanned;
-use crate::utils::{in_macro, snippet, span_lint_and_sugg};
+use syntax::source_map::Spanned;
 
-/// **What it does:** Checks for operations where precedence may be unclear
-/// and suggests to add parentheses. Currently it catches the following:
-/// * mixed usage of arithmetic and bit shifting/combining operators without
-/// parentheses
-/// * a "negative" numeric literal (which is really a unary `-` followed by a
-/// numeric literal)
-///   followed by a method call
-///
-/// **Why is this bad?** Not everyone knows the precedence of those operators by
-/// heart, so expressions like these may trip others trying to reason about the
-/// code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
-/// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
 declare_clippy_lint! {
+    /// **What it does:** Checks for operations where precedence may be unclear
+    /// and suggests to add parentheses. Currently it catches the following:
+    /// * mixed usage of arithmetic and bit shifting/combining operators without
+    /// parentheses
+    /// * a "negative" numeric literal (which is really a unary `-` followed by a
+    /// numeric literal)
+    ///   followed by a method call
+    ///
+    /// **Why is this bad?** Not everyone knows the precedence of those operators by
+    /// heart, so expressions like these may trip others trying to reason about the
+    /// code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
+    /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
     pub PRECEDENCE,
     complexity,
     "operations where precedence may be unclear"
 }
 
-#[derive(Copy, Clone)]
-pub struct Precedence;
-
-impl LintPass for Precedence {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(PRECEDENCE)
-    }
-}
+declare_lint_pass!(Precedence => [PRECEDENCE]);
 
 impl EarlyLintPass for Precedence {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_macro(expr.span) {
+        if in_macro_or_desugar(expr.span) {
             return;
         }
 
         if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node {
-            let span_sugg = |expr: &Expr, sugg| {
+            let span_sugg = |expr: &Expr, sugg, appl| {
                 span_lint_and_sugg(
                     cx,
                     PRECEDENCE,
@@ -51,39 +45,41 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
                     "operator precedence can trip the unwary",
                     "consider parenthesizing your expression",
                     sugg,
+                    appl,
                 );
             };
 
             if !is_bit_op(op) {
                 return;
             }
+            let mut applicability = Applicability::MachineApplicable;
             match (is_arith_expr(left), is_arith_expr(right)) {
                 (true, true) => {
                     let sugg = format!(
                         "({}) {} ({})",
-                        snippet(cx, left.span, ".."),
+                        snippet_with_applicability(cx, left.span, "..", &mut applicability),
                         op.to_string(),
-                        snippet(cx, right.span, "..")
+                        snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
-                    span_sugg(expr, sugg);
+                    span_sugg(expr, sugg, applicability);
                 },
                 (true, false) => {
                     let sugg = format!(
                         "({}) {} {}",
-                        snippet(cx, left.span, ".."),
+                        snippet_with_applicability(cx, left.span, "..", &mut applicability),
                         op.to_string(),
-                        snippet(cx, right.span, "..")
+                        snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
-                    span_sugg(expr, sugg);
+                    span_sugg(expr, sugg, applicability);
                 },
                 (false, true) => {
                     let sugg = format!(
                         "{} {} ({})",
-                        snippet(cx, left.span, ".."),
+                        snippet_with_applicability(cx, left.span, "..", &mut applicability),
                         op.to_string(),
-                        snippet(cx, right.span, "..")
+                        snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
-                    span_sugg(expr, sugg);
+                    span_sugg(expr, sugg, applicability);
                 },
                 (false, false) => (),
             }
@@ -95,13 +91,18 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
                     if let ExprKind::Lit(ref lit) = slf.node {
                         match lit.node {
                             LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => {
+                                let mut applicability = Applicability::MachineApplicable;
                                 span_lint_and_sugg(
                                     cx,
                                     PRECEDENCE,
                                     expr.span,
                                     "unary minus has lower precedence than method call",
                                     "consider adding parentheses to clarify your intent",
-                                    format!("-({})", snippet(cx, rhs.span, "..")),
+                                    format!(
+                                        "-({})",
+                                        snippet_with_applicability(cx, rhs.span, "..", &mut applicability)
+                                    ),
+                                    applicability,
                                 );
                             },
                             _ => (),
index ea2d07df45577a655f0c526bb2f956f2f5c7b646..8a6933b2f5a4f652fb2e4b5dcb712d5b8121022b 100644 (file)
 //! Checks for usage of  `&Vec[_]` and `&String`.
 
-use std::borrow::Cow;
-use rustc::hir::*;
-use rustc::hir::map::NodeItem;
-use rustc::hir::QPath;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::ptr::get_spans;
+use crate::utils::sym;
+use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
 use if_chain::if_chain;
+use rustc::hir::QPath;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use syntax::ast::NodeId;
-use syntax::codemap::Span;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use std::borrow::Cow;
+use syntax::source_map::Span;
 use syntax_pos::MultiSpan;
-use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
-use crate::utils::ptr::get_spans;
 
-/// **What it does:** This lint checks for function arguments of type `&String`
-/// or `&Vec` unless the references are mutable. It will also suggest you
-/// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
-/// calls.
-///
-/// **Why is this bad?** Requiring the argument to be of the specific size
-/// makes the function less useful for no benefit; slices in the form of `&[T]`
-/// or `&str` usually suffice and can be obtained from other types, too.
-///
-/// **Known problems:** The lint does not follow data. So if you have an
-/// argument `x` and write `let y = x; y.clone()` the lint will not suggest
-/// changing that `.clone()` to `.to_owned()`.
-///
-/// Other functions called from this function taking a `&String` or `&Vec`
-/// argument may also fail to compile if you change the argument. Applying
-/// this lint on them will fix the problem, but they may be in other crates.
-///
-/// Also there may be `fn(&Vec)`-typed references pointing to your function.
-/// If you have them, you will get a compiler error after applying this lint's
-/// suggestions. You then have the choice to undo your changes or change the
-/// type of the reference.
-///
-/// Note that if the function is part of your public interface, there may be
-/// other crates referencing it you may not be aware. Carefully deprecate the
-/// function before applying the lint suggestions in this case.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(&Vec<u32>) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint checks for function arguments of type `&String`
+    /// or `&Vec` unless the references are mutable. It will also suggest you
+    /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
+    /// calls.
+    ///
+    /// **Why is this bad?** Requiring the argument to be of the specific size
+    /// makes the function less useful for no benefit; slices in the form of `&[T]`
+    /// or `&str` usually suffice and can be obtained from other types, too.
+    ///
+    /// **Known problems:** The lint does not follow data. So if you have an
+    /// argument `x` and write `let y = x; y.clone()` the lint will not suggest
+    /// changing that `.clone()` to `.to_owned()`.
+    ///
+    /// Other functions called from this function taking a `&String` or `&Vec`
+    /// argument may also fail to compile if you change the argument. Applying
+    /// this lint on them will fix the problem, but they may be in other crates.
+    ///
+    /// Also there may be `fn(&Vec)`-typed references pointing to your function.
+    /// If you have them, you will get a compiler error after applying this lint's
+    /// suggestions. You then have the choice to undo your changes or change the
+    /// type of the reference.
+    ///
+    /// Note that if the function is part of your public interface, there may be
+    /// other crates referencing it you may not be aware. Carefully deprecate the
+    /// function before applying the lint suggestions in this case.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// fn foo(&Vec<u32>) { .. }
+    /// ```
     pub PTR_ARG,
     style,
-    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
-     instead, respectively"
+    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
 }
 
-/// **What it does:** This lint checks for equality comparisons with `ptr::null`
-///
-/// **Why is this bad?** It's easier and more readable to use the inherent
-/// `.is_null()`
-/// method instead
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if x == ptr::null { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint checks for equality comparisons with `ptr::null`
+    ///
+    /// **Why is this bad?** It's easier and more readable to use the inherent
+    /// `.is_null()`
+    /// method instead
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if x == ptr::null {
+    ///     ..
+    /// }
+    /// ```
     pub CMP_NULL,
     style,
     "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead."
 }
 
-/// **What it does:** This lint checks for functions that take immutable
-/// references and return
-/// mutable ones.
-///
-/// **Why is this bad?** This is trivially unsound, as one can create two
-/// mutable references
-/// from the same (immutable!) source. This
-/// [error](https://github.com/rust-lang/rust/issues/39465)
-/// actually lead to an interim Rust release 1.15.1.
-///
-/// **Known problems:** To be on the conservative side, if there's at least one
-/// mutable reference
-/// with the output lifetime, this lint will not trigger. In practice, this
-/// case is unlikely anyway.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(&Foo) -> &mut Bar { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint checks for functions that take immutable
+    /// references and return
+    /// mutable ones.
+    ///
+    /// **Why is this bad?** This is trivially unsound, as one can create two
+    /// mutable references
+    /// from the same (immutable!) source. This
+    /// [error](https://github.com/rust-lang/rust/issues/39465)
+    /// actually lead to an interim Rust release 1.15.1.
+    ///
+    /// **Known problems:** To be on the conservative side, if there's at least one
+    /// mutable reference
+    /// with the output lifetime, this lint will not trigger. In practice, this
+    /// case is unlikely anyway.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// fn foo(&Foo) -> &mut Bar { .. }
+    /// ```
     pub MUT_FROM_REF,
     correctness,
     "fns that create mutable refs from immutable ref args"
 }
 
-#[derive(Copy, Clone)]
-pub struct PointerPass;
-
-impl LintPass for PointerPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(PTR_ARG, CMP_NULL, MUT_FROM_REF)
-    }
-}
+declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PointerPass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ptr {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if let ItemKind::Fn(ref decl, _, _, body_id) = item.node {
-            check_fn(cx, decl, item.id, Some(body_id));
+            check_fn(cx, decl, item.hir_id, Some(body_id));
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx ImplItem) {
         if let ImplItemKind::Method(ref sig, body_id) = item.node {
-            if let Some(NodeItem(it)) = cx.tcx.hir.find(cx.tcx.hir.get_parent(item.id)) {
+            let parent_item = cx.tcx.hir().get_parent_item(item.hir_id);
+            if let Some(Node::Item(it)) = cx.tcx.hir().find_by_hir_id(parent_item) {
                 if let ItemKind::Impl(_, _, _, _, Some(_), _, _) = it.node {
                     return; // ignore trait impls
                 }
             }
-            check_fn(cx, &sig.decl, item.id, Some(body_id));
+            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
         }
     }
 
@@ -128,7 +123,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem
             } else {
                 None
             };
-            check_fn(cx, &sig.decl, item.id, body_id);
+            check_fn(cx, &sig.decl, item.hir_id, body_id);
         }
     }
 
@@ -146,19 +141,15 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option<BodyId>) {
-    let fn_def_id = cx.tcx.hir.local_def_id(fn_id);
+#[allow(clippy::too_many_lines)]
+fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: HirId, opt_body_id: Option<BodyId>) {
+    let fn_def_id = cx.tcx.hir().local_def_id_from_hir_id(fn_id);
     let sig = cx.tcx.fn_sig(fn_def_id);
     let fn_ty = sig.skip_binder();
 
     for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
-        if let ty::TyRef(
-            _,
-            ty,
-            MutImmutable
-        ) = ty.sty
-        {
-            if match_type(cx, ty, &paths::VEC) {
+        if let ty::Ref(_, ty, MutImmutable) = ty.sty {
+            if match_type(cx, ty, &*paths::VEC) {
                 let mut ty_snippet = None;
                 if_chain! {
                     if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).node;
@@ -173,7 +164,7 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
                         }
                     }
                 };
-                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
+                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[(*sym::clone, ".to_owned()")]) {
                     span_lint_and_then(
                         cx,
                         PTR_ARG,
@@ -182,44 +173,54 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
                          with non-Vec-based slices.",
                         |db| {
                             if let Some(ref snippet) = ty_snippet {
-                                db.span_suggestion(arg.span, "change this to", format!("&[{}]", snippet));
+                                db.span_suggestion(
+                                    arg.span,
+                                    "change this to",
+                                    format!("&[{}]", snippet),
+                                    Applicability::Unspecified,
+                                );
                             }
                             for (clonespan, suggestion) in spans {
                                 db.span_suggestion(
                                     clonespan,
-                                    &snippet_opt(cx, clonespan).map_or(
-                                        "change the call to".into(),
-                                        |x| Cow::Owned(format!("change `{}` to", x)),
-                                    ),
+                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
+                                        Cow::Owned(format!("change `{}` to", x))
+                                    }),
                                     suggestion.into(),
+                                    Applicability::Unspecified,
                                 );
                             }
                         },
                     );
                 }
-            } else if match_type(cx, ty, &paths::STRING) {
-                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
+            } else if match_type(cx, ty, &*paths::STRING) {
+                if let Some(spans) = get_spans(
+                    cx,
+                    opt_body_id,
+                    idx,
+                    &[(*sym::clone, ".to_string()"), (*sym::as_str, "")],
+                ) {
                     span_lint_and_then(
                         cx,
                         PTR_ARG,
                         arg.span,
                         "writing `&String` instead of `&str` involves a new object where a slice will do.",
                         |db| {
-                            db.span_suggestion(arg.span, "change this to", "&str".into());
+                            db.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
                             for (clonespan, suggestion) in spans {
                                 db.span_suggestion_short(
                                     clonespan,
-                                    &snippet_opt(cx, clonespan).map_or(
-                                        "change the call to".into(),
-                                        |x| Cow::Owned(format!("change `{}` to", x)),
-                                    ),
+                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
+                                        Cow::Owned(format!("change `{}` to", x))
+                                    }),
                                     suggestion.into(),
+                                    Applicability::Unspecified,
                                 );
                             }
                         },
                     );
                 }
-            } else if match_type(cx, ty, &paths::COW) {
+            } else if match_type(cx, ty, &*paths::COW) {
                 if_chain! {
                     if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.node;
                     if let TyKind::Path(ref path) = ty.node;
@@ -229,7 +230,7 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
                     if !params.parenthesized;
                     if let Some(inner) = params.args.iter().find_map(|arg| match arg {
                         GenericArg::Type(ty) => Some(ty),
-                        GenericArg::Lifetime(_) => None,
+                        _ => None,
                     });
                     then {
                         let replacement = snippet_opt(cx, inner.span);
@@ -240,7 +241,12 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
                                 arg.span,
                                 "using a reference to `Cow` is not recommended.",
                                 |db| {
-                                    db.span_suggestion(arg.span, "change this to", "&".to_owned() + &r);
+                                    db.span_suggestion(
+                                        arg.span,
+                                        "change this to",
+                                        "&".to_owned() + &r,
+                                        Applicability::Unspecified,
+                                    );
                                 },
                             );
                         }
@@ -253,7 +259,8 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
     if let FunctionRetTy::Return(ref ty) = decl.output {
         if let Some((out, MutMutable, _)) = get_rptr_lm(ty) {
             let mut immutables = vec![];
-            for (_, ref mutbl, ref argspan) in decl.inputs
+            for (_, ref mutbl, ref argspan) in decl
+                .inputs
                 .iter()
                 .filter_map(|ty| get_rptr_lm(ty))
                 .filter(|&(lt, _, _)| lt.name == out.name)
@@ -266,10 +273,16 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
             if immutables.is_empty() {
                 return;
             }
-            span_lint_and_then(cx, MUT_FROM_REF, ty.span, "mutable borrow from immutable input(s)", |db| {
-                let ms = MultiSpan::from_spans(immutables);
-                db.span_note(ms, "immutable borrow here");
-            });
+            span_lint_and_then(
+                cx,
+                MUT_FROM_REF,
+                ty.span,
+                "mutable borrow from immutable input(s)",
+                |db| {
+                    let ms = MultiSpan::from_spans(immutables);
+                    db.span_note(ms, "immutable borrow here");
+                },
+            );
         }
     }
 }
@@ -286,7 +299,7 @@ fn is_null_path(expr: &Expr) -> bool {
     if let ExprKind::Call(ref pathexp, ref args) = expr.node {
         if args.is_empty() {
             if let ExprKind::Path(ref path) = pathexp.node {
-                return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT);
+                return match_qpath(path, &*paths::PTR_NULL) || match_qpath(path, &*paths::PTR_NULL_MUT);
             }
         }
     }
diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs
new file mode 100644 (file)
index 0000000..f33347c
--- /dev/null
@@ -0,0 +1,150 @@
+use crate::utils;
+use crate::utils::sym;
+use rustc::hir::{Expr, ExprKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use std::fmt;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of the `offset` pointer method with a `usize` casted to an
+    /// `isize`.
+    ///
+    /// **Why is this bad?** If we’re always increasing the pointer address, we can avoid the numeric
+    /// cast by using the `add` method instead.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let vec = vec![b'a', b'b', b'c'];
+    /// let ptr = vec.as_ptr();
+    /// let offset = 1_usize;
+    ///
+    /// unsafe {
+    ///     ptr.offset(offset as isize);
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// let vec = vec![b'a', b'b', b'c'];
+    /// let ptr = vec.as_ptr();
+    /// let offset = 1_usize;
+    ///
+    /// unsafe {
+    ///     ptr.add(offset);
+    /// }
+    /// ```
+    pub PTR_OFFSET_WITH_CAST,
+    complexity,
+    "unneeded pointer offset cast"
+}
+
+declare_lint_pass!(PtrOffsetWithCast => [PTR_OFFSET_WITH_CAST]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PtrOffsetWithCast {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        // Check if the expressions is a ptr.offset or ptr.wrapping_offset method call
+        let (receiver_expr, arg_expr, method) = match expr_as_ptr_offset_call(cx, expr) {
+            Some(call_arg) => call_arg,
+            None => return,
+        };
+
+        // Check if the argument to the method call is a cast from usize
+        let cast_lhs_expr = match expr_as_cast_from_usize(cx, arg_expr) {
+            Some(cast_lhs_expr) => cast_lhs_expr,
+            None => return,
+        };
+
+        let msg = format!("use of `{}` with a `usize` casted to an `isize`", method);
+        if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) {
+            utils::span_lint_and_sugg(
+                cx,
+                PTR_OFFSET_WITH_CAST,
+                expr.span,
+                &msg,
+                "try",
+                sugg,
+                Applicability::MachineApplicable,
+            );
+        } else {
+            utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg);
+        }
+    }
+}
+
+// If the given expression is a cast from a usize, return the lhs of the cast
+fn expr_as_cast_from_usize<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> Option<&'tcx Expr> {
+    if let ExprKind::Cast(ref cast_lhs_expr, _) = expr.node {
+        if is_expr_ty_usize(cx, &cast_lhs_expr) {
+            return Some(cast_lhs_expr);
+        }
+    }
+    None
+}
+
+// If the given expression is a ptr::offset  or ptr::wrapping_offset method call, return the
+// receiver, the arg of the method call, and the method.
+fn expr_as_ptr_offset_call<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    expr: &'tcx Expr,
+) -> Option<(&'tcx Expr, &'tcx Expr, Method)> {
+    if let ExprKind::MethodCall(ref path_segment, _, ref args) = expr.node {
+        if is_expr_ty_raw_ptr(cx, &args[0]) {
+            if path_segment.ident.name == *sym::offset {
+                return Some((&args[0], &args[1], Method::Offset));
+            }
+            if path_segment.ident.name == *sym::wrapping_offset {
+                return Some((&args[0], &args[1], Method::WrappingOffset));
+            }
+        }
+    }
+    None
+}
+
+// Is the type of the expression a usize?
+fn is_expr_ty_usize<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr) -> bool {
+    cx.tables.expr_ty(expr) == cx.tcx.types.usize
+}
+
+// Is the type of the expression a raw pointer?
+fn is_expr_ty_raw_ptr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr) -> bool {
+    cx.tables.expr_ty(expr).is_unsafe_ptr()
+}
+
+fn build_suggestion<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    method: Method,
+    receiver_expr: &Expr,
+    cast_lhs_expr: &Expr,
+) -> Option<String> {
+    let receiver = utils::snippet_opt(cx, receiver_expr.span)?;
+    let cast_lhs = utils::snippet_opt(cx, cast_lhs_expr.span)?;
+    Some(format!("{}.{}({})", receiver, method.suggestion(), cast_lhs))
+}
+
+#[derive(Copy, Clone)]
+enum Method {
+    Offset,
+    WrappingOffset,
+}
+
+impl Method {
+    fn suggestion(self) -> &'static str {
+        match self {
+            Method::Offset => "add",
+            Method::WrappingOffset => "wrapping_add",
+        }
+    }
+}
+
+impl fmt::Display for Method {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Method::Offset => write!(f, "offset"),
+            Method::WrappingOffset => write!(f, "wrapping_offset"),
+        }
+    }
+}
index 630dd1b57be1660cb01c858f71efcd1dd494f93e..1949101def9e9a793a5b4aee141c9d42b6ebaea2 100644 (file)
@@ -1,49 +1,44 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::*;
-use rustc::hir::def::Def;
-use crate::utils::sugg::Sugg;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ptr::P;
 
-use crate::utils::{match_def_path, match_type, span_lint_and_then};
 use crate::utils::paths::*;
+use crate::utils::sugg::Sugg;
+use crate::utils::sym;
+use crate::utils::{higher, match_def_path, match_type, span_lint_and_then, SpanlessEq};
 
-/// **What it does:** Checks for expressions that could be replaced by the question mark operator
-///
-/// **Why is this bad?** Question mark usage is more idiomatic
-///
-/// **Known problems:** None
-///
-/// **Example:**
-/// ```rust
-/// if option.is_none() {
-///     return None;
-/// }
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// option?;
-/// ```
-declare_clippy_lint!{
+declare_clippy_lint! {
+    /// **What it does:** Checks for expressions that could be replaced by the question mark operator.
+    ///
+    /// **Why is this bad?** Question mark usage is more idiomatic.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// if option.is_none() {
+    ///     return None;
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```ignore
+    /// option?;
+    /// ```
     pub QUESTION_MARK,
     style,
     "checks for expressions that could be replaced by the question mark operator"
 }
 
-#[derive(Copy, Clone)]
-pub struct QuestionMarkPass;
+declare_lint_pass!(QuestionMark => [QUESTION_MARK]);
 
-impl LintPass for QuestionMarkPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(QUESTION_MARK)
-    }
-}
-
-impl QuestionMarkPass {
-    /// Check if the given expression on the given context matches the following structure:
+impl QuestionMark {
+    /// Checks if the given expression on the given context matches the following structure:
     ///
     /// ```ignore
     /// if option.is_none() {
@@ -54,37 +49,62 @@ impl QuestionMarkPass {
     /// If it matches, it will suggest to use the question mark operator instead
     fn check_is_none_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr) {
         if_chain! {
-            if let ExprKind::If(ref if_expr, ref body, _) = expr.node;
-            if let ExprKind::MethodCall(ref segment, _, ref args) = if_expr.node;
-            if segment.ident.name == "is_none";
+            if let Some((if_expr, body, else_)) = higher::if_block(&expr);
+            if let ExprKind::MethodCall(segment, _, args) = &if_expr.node;
+            if segment.ident.name == *sym::is_none;
             if Self::expression_returns_none(cx, body);
             if let Some(subject) = args.get(0);
             if Self::is_option(cx, subject);
 
             then {
-                span_lint_and_then(
-                    cx,
-                    QUESTION_MARK,
-                    expr.span,
-                    "this block may be rewritten with the `?` operator",
-                    |db| {
-                        let receiver_str = &Sugg::hir(cx, subject, "..");
-
-                        db.span_suggestion(
-                            expr.span,
-                            "replace_it_with",
-                            format!("{}?;", receiver_str),
-                        );
+                let receiver_str = &Sugg::hir(cx, subject, "..");
+                let mut replacement: Option<String> = None;
+                if let Some(else_) = else_ {
+                    if_chain! {
+                        if let ExprKind::Block(block, None) = &else_.node;
+                        if block.stmts.len() == 0;
+                        if let Some(block_expr) = &block.expr;
+                        if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
+                        then {
+                            replacement = Some(format!("Some({}?)", receiver_str));
+                        }
                     }
-                )
+                } else if Self::moves_by_default(cx, subject) {
+                        replacement = Some(format!("{}.as_ref()?;", receiver_str));
+                } else {
+                        replacement = Some(format!("{}?;", receiver_str));
+                }
+
+                if let Some(replacement_str) = replacement {
+                    span_lint_and_then(
+                        cx,
+                        QUESTION_MARK,
+                        expr.span,
+                        "this block may be rewritten with the `?` operator",
+                        |db| {
+                            db.span_suggestion(
+                                expr.span,
+                                "replace_it_with",
+                                replacement_str,
+                                Applicability::MaybeIncorrect, // snippet
+                            );
+                        }
+                    )
+               }
             }
         }
     }
 
+    fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
+        let expr_ty = cx.tables.expr_ty(expression);
+
+        !expr_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, expression.span)
+    }
+
     fn is_option(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
         let expr_ty = cx.tables.expr_ty(expression);
 
-        match_type(cx, expr_ty, &OPTION)
+        match_type(cx, expr_ty, &*OPTION)
     }
 
     fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
@@ -96,17 +116,17 @@ fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr) -> bool
 
                 false
             },
-            ExprKind::Ret(Some(ref expr)) => {
-                Self::expression_returns_none(cx, expr)
-            },
+            ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
             ExprKind::Path(ref qp) => {
-                if let Def::VariantCtor(def_id, _) = cx.tables.qpath_def(qp, expression.hir_id) {
-                    return match_def_path(cx.tcx, def_id,  &OPTION_NONE);
+                if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
+                    cx.tables.qpath_res(qp, expression.hir_id)
+                {
+                    return match_def_path(cx, def_id, &*OPTION_NONE);
                 }
 
                 false
             },
-            _ => false
+            _ => false,
         }
     }
 
@@ -115,7 +135,7 @@ fn return_expression(block: &Block) -> Option<P<Expr>> {
         if_chain! {
             if block.stmts.len() == 1;
             if let Some(expr) = block.stmts.iter().last();
-            if let StmtKind::Semi(ref expr, _) = expr.node;
+            if let StmtKind::Semi(ref expr) = expr.node;
             if let ExprKind::Ret(ref ret_expr) = expr.node;
             if let &Some(ref ret_expr) = ret_expr;
 
@@ -124,16 +144,20 @@ fn return_expression(block: &Block) -> Option<P<Expr>> {
             }
         }
 
-        // Check if the block has an implicit return expression
-        if let Some(ref ret_expr) = block.expr {
-            return Some(ret_expr.clone());
+        // Check for `return` without a semicolon.
+        if_chain! {
+            if block.stmts.len() == 0;
+            if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.node);
+            then {
+                return Some(ret_expr.clone());
+            }
         }
 
         None
     }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for QuestionMarkPass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for QuestionMark {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         Self::check_is_none_and_early_return_none(cx, expr);
     }
index fd303bb6ab4f8dd39ebde8de2e3dada1c9b32e5a..d5e71fdbec326317faf45b737bbfdc2426b7b4e4 100644 (file)
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
 use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ast::RangeLimits;
-use syntax::codemap::Spanned;
-use crate::utils::{is_integer_literal, paths, snippet, span_lint, span_lint_and_then};
-use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
+use syntax::source_map::Spanned;
+
 use crate::utils::sugg::Sugg;
+use crate::utils::sym;
+use crate::utils::{get_trait_def_id, higher, implements_trait, SpanlessEq};
+use crate::utils::{is_integer_literal, paths, snippet, snippet_opt, span_lint, span_lint_and_then};
 
-/// **What it does:** Checks for calling `.step_by(0)` on iterators,
-/// which never terminates.
-///
-/// **Why is this bad?** This very much looks like an oversight, since with
-/// `loop { .. }` there is an obvious better way to endlessly loop.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for x in (5..5).step_by(0) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calling `.step_by(0)` on iterators,
+    /// which never terminates.
+    ///
+    /// **Why is this bad?** This very much looks like an oversight, since with
+    /// `loop { .. }` there is an obvious better way to endlessly loop.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// for x in (5..5).step_by(0) {
+    ///     ..
+    /// }
+    /// ```
     pub ITERATOR_STEP_BY_ZERO,
     correctness,
     "using `Iterator::step_by(0)`, which produces an infinite iterator"
 }
 
-/// **What it does:** Checks for zipping a collection with the range of
-/// `0.._.len()`.
-///
-/// **Why is this bad?** The code is better expressed with `.enumerate()`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// x.iter().zip(0..x.len())
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for zipping a collection with the range of
+    /// `0.._.len()`.
+    ///
+    /// **Why is this bad?** The code is better expressed with `.enumerate()`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// x.iter().zip(0..x.len())
+    /// ```
     pub RANGE_ZIP_WITH_LEN,
     complexity,
     "zipping iterator with a range when `enumerate()` would do"
 }
 
-/// **What it does:** Checks for exclusive ranges where 1 is added to the
-/// upper bound, e.g. `x..(y+1)`.
-///
-/// **Why is this bad?** The code is more readable with an inclusive range
-/// like `x..=y`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for x..(y+1) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for exclusive ranges where 1 is added to the
+    /// upper bound, e.g., `x..(y+1)`.
+    ///
+    /// **Why is this bad?** The code is more readable with an inclusive range
+    /// like `x..=y`.
+    ///
+    /// **Known problems:** Will add unnecessary pair of parentheses when the
+    /// expression is not wrapped in a pair but starts with a opening parenthesis
+    /// and ends with a closing one.
+    /// I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// for x..(y+1) { .. }
+    /// ```
     pub RANGE_PLUS_ONE,
-    nursery,
+    complexity,
     "`x..(y+1)` reads better as `x..=y`"
 }
 
-/// **What it does:** Checks for inclusive ranges where 1 is subtracted from
-/// the upper bound, e.g. `x..=(y-1)`.
-///
-/// **Why is this bad?** The code is more readable with an exclusive range
-/// like `x..y`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// for x..=(y-1) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for inclusive ranges where 1 is subtracted from
+    /// the upper bound, e.g., `x..=(y-1)`.
+    ///
+    /// **Why is this bad?** The code is more readable with an exclusive range
+    /// like `x..y`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// for x..=(y-1) { .. }
+    /// ```
     pub RANGE_MINUS_ONE,
-    style,
+    complexity,
     "`x..=(y-1)` reads better as `x..y`"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
+declare_lint_pass!(Ranges => [
+    ITERATOR_STEP_BY_ZERO,
+    RANGE_ZIP_WITH_LEN,
+    RANGE_PLUS_ONE,
+    RANGE_MINUS_ONE
+]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ITERATOR_STEP_BY_ZERO, RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ranges {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::MethodCall(ref path, _, ref args) = expr.node {
             let name = path.ident.as_str();
@@ -108,16 +114,16 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 let iter = &args[0].node;
                 let zip_arg = &args[1];
                 if_chain! {
-                    // .iter() call
+                    // `.iter()` call
                     if let ExprKind::MethodCall(ref iter_path, _, ref iter_args ) = *iter;
-                    if iter_path.ident.name == "iter";
-                    // range expression in .zip() call: 0..x.len()
+                    if iter_path.ident.name == *sym::iter;
+                    // range expression in `.zip()` call: `0..x.len()`
                     if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
                     if is_integer_literal(start, 0);
-                    // .len() call
+                    // `.len()` call
                     if let ExprKind::MethodCall(ref len_path, _, ref len_args) = end.node;
-                    if len_path.ident.name == "len" && len_args.len() == 1;
-                    // .iter() and .len() called on same Path
+                    if len_path.ident.name == *sym::len && len_args.len() == 1;
+                    // `.iter()` and `.len()` called on same `Path`
                     if let ExprKind::Path(QPath::Resolved(_, ref iter_path)) = iter_args[0].node;
                     if let ExprKind::Path(QPath::Resolved(_, ref len_path)) = len_args[0].node;
                     if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
@@ -132,28 +138,51 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             }
         }
 
-        // exclusive range plus one: x..(y+1)
+        // exclusive range plus one: `x..(y+1)`
         if_chain! {
-            if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::HalfOpen }) = higher::range(cx, expr);
+            if let Some(higher::Range {
+                start,
+                end: Some(end),
+                limits: RangeLimits::HalfOpen
+            }) = higher::range(cx, expr);
             if let Some(y) = y_plus_one(end);
             then {
+                let span = expr.span
+                    .ctxt()
+                    .outer()
+                    .expn_info()
+                    .map_or(expr.span, |info| info.call_site);
                 span_lint_and_then(
                     cx,
                     RANGE_PLUS_ONE,
-                    expr.span,
+                    span,
                     "an inclusive range would be more readable",
                     |db| {
-                        let start = start.map_or("".to_owned(), |x| Sugg::hir(cx, x, "x").to_string());
+                        let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string());
                         let end = Sugg::hir(cx, y, "y");
-                        db.span_suggestion(expr.span,
-                                           "use",
-                                           format!("{}..={}", start, end));
+                        if let Some(is_wrapped) = &snippet_opt(cx, span) {
+                            if is_wrapped.starts_with('(') && is_wrapped.ends_with(')') {
+                                db.span_suggestion(
+                                    span,
+                                    "use",
+                                    format!("({}..={})", start, end),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                db.span_suggestion(
+                                    span,
+                                    "use",
+                                    format!("{}..={}", start, end),
+                                    Applicability::MachineApplicable, // snippet
+                                );
+                            }
+                        }
                     },
                 );
             }
         }
 
-        // inclusive range minus one: x..=(y-1)
+        // inclusive range minus one: `x..=(y-1)`
         if_chain! {
             if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
             if let Some(y) = y_minus_one(end);
@@ -164,11 +193,14 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                     expr.span,
                     "an exclusive range would be more readable",
                     |db| {
-                        let start = start.map_or("".to_owned(), |x| Sugg::hir(cx, x, "x").to_string());
+                        let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").to_string());
                         let end = Sugg::hir(cx, y, "y");
-                        db.span_suggestion(expr.span,
-                                           "use",
-                                           format!("{}..{}", start, end));
+                        db.span_suggestion(
+                            expr.span,
+                            "use",
+                            format!("{}..{}", start, end),
+                            Applicability::MachineApplicable, // snippet
+                        );
                     },
                 );
             }
@@ -177,21 +209,30 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
 }
 
 fn has_step_by(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
-    // No need for walk_ptrs_ty here because step_by moves self, so it
+    // No need for `walk_ptrs_ty` here because `step_by` moves `self`, so it
     // can't be called on a borrowed range.
     let ty = cx.tables.expr_ty_adjusted(expr);
 
-    get_trait_def_id(cx, &paths::ITERATOR).map_or(false, |iterator_trait| implements_trait(cx, ty, iterator_trait, &[]))
+    get_trait_def_id(cx, &*paths::ITERATOR)
+        .map_or(false, |iterator_trait| implements_trait(cx, ty, iterator_trait, &[]))
 }
 
 fn y_plus_one(expr: &Expr) -> Option<&Expr> {
     match expr.node {
-        ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref lhs, ref rhs) => if is_integer_literal(lhs, 1) {
-            Some(rhs)
-        } else if is_integer_literal(rhs, 1) {
-            Some(lhs)
-        } else {
-            None
+        ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Add, ..
+            },
+            ref lhs,
+            ref rhs,
+        ) => {
+            if is_integer_literal(lhs, 1) {
+                Some(rhs)
+            } else if is_integer_literal(rhs, 1) {
+                Some(lhs)
+            } else {
+                None
+            }
         },
         _ => None,
     }
@@ -199,7 +240,13 @@ fn y_plus_one(expr: &Expr) -> Option<&Expr> {
 
 fn y_minus_one(expr: &Expr) -> Option<&Expr> {
     match expr.node {
-        ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, ref lhs, ref rhs) if is_integer_literal(rhs, 1) => Some(lhs),
+        ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Sub, ..
+            },
+            ref lhs,
+            ref rhs,
+        ) if is_integer_literal(rhs, 1) => Some(lhs),
         _ => None,
     }
 }
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
new file mode 100644 (file)
index 0000000..53bfc15
--- /dev/null
@@ -0,0 +1,336 @@
+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,
+};
+use if_chain::if_chain;
+use matches::matches;
+use rustc::hir::intravisit::FnKind;
+use rustc::hir::{def_id, Body, FnDecl, HirId};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::mir::{
+    self, traversal,
+    visit::{MutatingUseContext, PlaceContext, Visitor},
+    TerminatorKind,
+};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use std::convert::TryFrom;
+use syntax::source_map::{BytePos, Span};
+
+macro_rules! unwrap_or_continue {
+    ($x:expr) => {
+        match $x {
+            Some(x) => x,
+            None => continue,
+        }
+    };
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for a redudant `clone()` (and its relatives) which clones an owned
+    /// value that is going to be dropped without further use.
+    ///
+    /// **Why is this bad?** It is not always possible for the compiler to eliminate useless
+    /// allocations and deallocations generated by redundant `clone()`s.
+    ///
+    /// **Known problems:**
+    ///
+    /// * Suggestions made by this lint could require NLL to be enabled.
+    /// * False-positive if there is a borrow preventing the value from moving out.
+    ///
+    /// ```rust
+    /// let x = String::new();
+    ///
+    /// let y = &x;
+    ///
+    /// foo(x.clone()); // This lint suggests to remove this `clone()`
+    /// ```
+    ///
+    /// **Example:**
+    /// ```rust
+    /// {
+    ///     let x = Foo::new();
+    ///     call(x.clone());
+    ///     call(x.clone()); // this can just pass `x`
+    /// }
+    ///
+    /// ["lorem", "ipsum"].join(" ").to_string()
+    ///
+    /// Path::new("/a/b").join("c").to_path_buf()
+    /// ```
+    pub REDUNDANT_CLONE,
+    nursery,
+    "`clone()` of an owned value that is going to be dropped immediately"
+}
+
+declare_lint_pass!(RedundantClone => [REDUNDANT_CLONE]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
+    #[allow(clippy::too_many_lines)]
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        _: FnKind<'tcx>,
+        _: &'tcx FnDecl,
+        body: &'tcx Body,
+        _: Span,
+        _: HirId,
+    ) {
+        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
+        let mir = cx.tcx.optimized_mir(def_id);
+
+        for (bb, bbdata) in mir.basic_blocks().iter_enumerated() {
+            let terminator = bbdata.terminator();
+
+            if in_macro_or_desugar(terminator.source_info.span) {
+                continue;
+            }
+
+            // Give up on loops
+            if terminator.successors().any(|s| *s == bb) {
+                continue;
+            }
+
+            let (fn_def_id, arg, arg_ty, _) = unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
+
+            let from_borrow = match_def_path(cx, fn_def_id, &*paths::CLONE_TRAIT_METHOD)
+                || match_def_path(cx, fn_def_id, &*paths::TO_OWNED_METHOD)
+                || (match_def_path(cx, fn_def_id, &*paths::TO_STRING_METHOD)
+                    && match_type(cx, arg_ty, &*paths::STRING));
+
+            let from_deref = !from_borrow
+                && (match_def_path(cx, fn_def_id, &*paths::PATH_TO_PATH_BUF)
+                    || match_def_path(cx, fn_def_id, &*paths::OS_STR_TO_OS_STRING));
+
+            if !from_borrow && !from_deref {
+                continue;
+            }
+
+            // _1 in MIR `{ _2 = &_1; clone(move _2); }` or `{ _2 = _1; to_path_buf(_2); } (from_deref)
+            // In case of `from_deref`, `arg` is already a reference since it is `deref`ed in the previous
+            // block.
+            let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(
+                cx,
+                mir,
+                arg,
+                from_borrow,
+                bbdata.statements.iter()
+            ));
+
+            if from_borrow && cannot_move_out {
+                continue;
+            }
+
+            // _1 in MIR `{ _2 = &_1; _3 = deref(move _2); } -> { _4 = _3; to_path_buf(move _4); }`
+            let referent = if from_deref {
+                let ps = mir.predecessors_for(bb);
+                if ps.len() != 1 {
+                    continue;
+                }
+                let pred_terminator = mir[ps[0]].terminator();
+
+                let pred_arg = if_chain! {
+                    if let Some((pred_fn_def_id, pred_arg, pred_arg_ty, Some(res))) =
+                        is_call_with_ref_arg(cx, mir, &pred_terminator.kind);
+                    if *res == mir::Place::Base(mir::PlaceBase::Local(cloned));
+                    if match_def_path(cx, pred_fn_def_id, &*paths::DEREF_TRAIT_METHOD);
+                    if match_type(cx, pred_arg_ty, &*paths::PATH_BUF)
+                        || match_type(cx, pred_arg_ty, &*paths::OS_STRING);
+                    then {
+                        pred_arg
+                    } else {
+                        continue;
+                    }
+                };
+
+                let (local, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(
+                    cx,
+                    mir,
+                    pred_arg,
+                    true,
+                    mir[ps[0]].statements.iter()
+                ));
+                if cannot_move_out {
+                    continue;
+                }
+                local
+            } else {
+                cloned
+            };
+
+            let used_later = traversal::ReversePostorder::new(&mir, bb).skip(1).any(|(tbb, tdata)| {
+                // Give up on loops
+                if tdata.terminator().successors().any(|s| *s == bb) {
+                    return true;
+                }
+
+                let mut vis = LocalUseVisitor {
+                    local: referent,
+                    used_other_than_drop: false,
+                };
+                vis.visit_basic_block_data(tbb, tdata);
+                vis.used_other_than_drop
+            });
+
+            if !used_later {
+                let span = terminator.source_info.span;
+                let node = if let mir::ClearCrossCrate::Set(scope_local_data) = &mir.source_scope_local_data {
+                    scope_local_data[terminator.source_info.scope].lint_root
+                } else {
+                    unreachable!()
+                };
+
+                if_chain! {
+                    if let Some(snip) = snippet_opt(cx, span);
+                    if let Some(dot) = snip.rfind('.');
+                    then {
+                        let sugg_span = span.with_lo(
+                            span.lo() + BytePos(u32::try_from(dot).unwrap())
+                        );
+
+                        span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |db| {
+                            db.span_suggestion(
+                                sugg_span,
+                                "remove this",
+                                String::new(),
+                                Applicability::MaybeIncorrect,
+                            );
+                            db.span_note(
+                                span.with_hi(span.lo() + BytePos(u32::try_from(dot).unwrap())),
+                                "this value is dropped without further use",
+                            );
+                        });
+                    } else {
+                        span_lint_hir(cx, REDUNDANT_CLONE, node, span, "redundant clone");
+                    }
+                }
+            }
+        }
+    }
+}
+
+/// If `kind` is `y = func(x: &T)` where `T: !Copy`, returns `(DefId of func, x, T, y)`.
+fn is_call_with_ref_arg<'tcx>(
+    cx: &LateContext<'_, 'tcx>,
+    mir: &'tcx mir::Mir<'tcx>,
+    kind: &'tcx mir::TerminatorKind<'tcx>,
+) -> Option<(def_id::DefId, mir::Local, Ty<'tcx>, Option<&'tcx mir::Place<'tcx>>)> {
+    if_chain! {
+        if let TerminatorKind::Call { func, args, destination, .. } = kind;
+        if args.len() == 1;
+        if let mir::Operand::Move(mir::Place::Base(mir::PlaceBase::Local(local))) = &args[0];
+        if let ty::FnDef(def_id, _) = func.ty(&*mir, cx.tcx).sty;
+        if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx));
+        if !is_copy(cx, inner_ty);
+        then {
+            Some((def_id, *local, inner_ty, destination.as_ref().map(|(dest, _)| dest)))
+        } else {
+            None
+        }
+    }
+}
+
+type CannotMoveOut = bool;
+
+/// Finds the first `to = (&)from`, and returns
+/// ``Some((from, [`true` if `from` cannot be moved out]))``.
+fn find_stmt_assigns_to<'a, 'tcx: 'a>(
+    cx: &LateContext<'_, 'tcx>,
+    mir: &mir::Mir<'tcx>,
+    to: mir::Local,
+    by_ref: bool,
+    stmts: impl DoubleEndedIterator<Item = &'a mir::Statement<'tcx>>,
+) -> Option<(mir::Local, CannotMoveOut)> {
+    stmts
+        .rev()
+        .find_map(|stmt| {
+            if let mir::StatementKind::Assign(mir::Place::Base(mir::PlaceBase::Local(local)), v) = &stmt.kind {
+                if *local == to {
+                    return Some(v);
+                }
+            }
+
+            None
+        })
+        .and_then(|v| {
+            if by_ref {
+                if let mir::Rvalue::Ref(_, _, ref place) = **v {
+                    return base_local_and_movability(cx, mir, place);
+                }
+            } else if let mir::Rvalue::Use(mir::Operand::Copy(ref place)) = **v {
+                return base_local_and_movability(cx, mir, place);
+            }
+            None
+        })
+}
+
+/// Extracts and returns the undermost base `Local` of given `place`. Returns `place` itself
+/// if it is already a `Local`.
+///
+/// Also reports whether given `place` cannot be moved out.
+fn base_local_and_movability<'tcx>(
+    cx: &LateContext<'_, 'tcx>,
+    mir: &mir::Mir<'tcx>,
+    mut place: &mir::Place<'tcx>,
+) -> Option<(mir::Local, CannotMoveOut)> {
+    use rustc::mir::Place::*;
+    use rustc::mir::PlaceBase;
+
+    // Dereference. You cannot move things out from a borrowed value.
+    let mut deref = false;
+    // Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509.
+    let mut field = false;
+
+    loop {
+        match place {
+            Base(PlaceBase::Local(local)) => return Some((*local, deref || field)),
+            Projection(proj) => {
+                place = &proj.base;
+                deref = deref || matches!(proj.elem, mir::ProjectionElem::Deref);
+                if !field && matches!(proj.elem, mir::ProjectionElem::Field(..)) {
+                    field = has_drop(cx, place.ty(&mir.local_decls, cx.tcx).ty);
+                }
+            },
+            _ => return None,
+        }
+    }
+}
+
+struct LocalUseVisitor {
+    local: mir::Local,
+    used_other_than_drop: bool,
+}
+
+impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
+    fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
+        let statements = &data.statements;
+        for (statement_index, statement) in statements.iter().enumerate() {
+            self.visit_statement(statement, mir::Location { block, statement_index });
+
+            // Once flagged, skip remaining statements
+            if self.used_other_than_drop {
+                return;
+            }
+        }
+
+        self.visit_terminator(
+            data.terminator(),
+            mir::Location {
+                block,
+                statement_index: statements.len(),
+            },
+        );
+    }
+
+    fn visit_local(&mut self, local: &mir::Local, ctx: PlaceContext, _: mir::Location) {
+        match ctx {
+            PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_) => return,
+            _ => {},
+        }
+
+        if *local == self.local {
+            self.used_other_than_drop = true;
+        }
+    }
+}
index 4f28d36e2a8f72e66533d11f1ca709be7b937a84..389f72057890d26d505c32e4d290f7d7b7c34caf 100644 (file)
@@ -1,62 +1,61 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
-use crate::utils::{in_macro, is_range_expression, match_var, span_lint_and_sugg};
+use crate::utils::span_lint_and_sugg;
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::*;
 
-/// **What it does:** Checks for fields in struct literals where shorthands
-/// could be used.
-///
-/// **Why is this bad?** If the field and variable names are the same,
-/// the field name is redundant.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let bar: u8 = 123;
-///
-/// struct Foo {
-///     bar: u8,
-/// }
-///
-/// let foo = Foo{ bar: bar }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for fields in struct literals where shorthands
+    /// could be used.
+    ///
+    /// **Why is this bad?** If the field and variable names are the same,
+    /// the field name is redundant.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let bar: u8 = 123;
+    ///
+    /// struct Foo {
+    ///     bar: u8,
+    /// }
+    ///
+    /// let foo = Foo { bar: bar };
+    /// ```
+    /// the last line can be simplified to
+    /// ```ignore
+    /// let foo = Foo { bar };
+    /// ```
     pub REDUNDANT_FIELD_NAMES,
     style,
     "checks for fields in struct literals where shorthands could be used"
 }
 
-pub struct RedundantFieldNames;
-
-impl LintPass for RedundantFieldNames {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(REDUNDANT_FIELD_NAMES)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantFieldNames {
-    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        // Ignore all macros including range expressions.
-        // They can have redundant field names when expanded.
-        // e.g. range expression `start..end` is desugared to `Range { start: start, end: end }`
-        if in_macro(expr.span) || is_range_expression(expr.span) {
-            return;
-        }
+declare_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
 
+impl EarlyLintPass for RedundantFieldNames {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::Struct(_, ref fields, _) = expr.node {
             for field in fields {
-                let name = field.ident.name;
-
-                if match_var(&field.expr, name) && !field.is_shorthand {
-                    span_lint_and_sugg (
-                        cx,
-                        REDUNDANT_FIELD_NAMES,
-                        field.span,
-                        "redundant field names in struct initialization",
-                        "replace it with",
-                        name.to_string()
-                    );
+                if field.is_shorthand {
+                    continue;
+                }
+                if let ExprKind::Path(None, path) = &field.expr.node {
+                    if path.segments.len() == 1
+                        && path.segments[0].ident == field.ident
+                        && path.segments[0].args.is_none()
+                    {
+                        span_lint_and_sugg(
+                            cx,
+                            REDUNDANT_FIELD_NAMES,
+                            field.span,
+                            "redundant field names in struct initialization",
+                            "replace it with",
+                            field.ident.to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                    }
                 }
             }
         }
diff --git a/clippy_lints/src/redundant_pattern_matching.rs b/clippy_lints/src/redundant_pattern_matching.rs
new file mode 100644 (file)
index 0000000..9f47883
--- /dev/null
@@ -0,0 +1,195 @@
+use crate::utils::{match_qpath, paths, snippet, span_lint_and_then};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::LitKind;
+use syntax::ptr::P;
+use syntax::symbol::Symbol;
+
+declare_clippy_lint! {
+    /// **What it does:** Lint for redundant pattern matching over `Result` or
+    /// `Option`
+    ///
+    /// **Why is this bad?** It's more concise and clear to just use the proper
+    /// utility function
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// if let Ok(_) = Ok::<i32, i32>(42) {}
+    /// if let Err(_) = Err::<i32, i32>(42) {}
+    /// if let None = None::<()> {}
+    /// if let Some(_) = Some(42) {}
+    /// match Ok::<i32, i32>(42) {
+    ///     Ok(_) => true,
+    ///     Err(_) => false,
+    /// };
+    /// ```
+    ///
+    /// The more idiomatic use would be:
+    ///
+    /// ```rust
+    /// if Ok::<i32, i32>(42).is_ok() {}
+    /// if Err::<i32, i32>(42).is_err() {}
+    /// if None::<()>.is_none() {}
+    /// if Some(42).is_some() {}
+    /// Ok::<i32, i32>(42).is_ok();
+    /// ```
+    pub REDUNDANT_PATTERN_MATCHING,
+    style,
+    "use the proper utility function avoiding an `if let`"
+}
+
+declare_lint_pass!(RedundantPatternMatching => [REDUNDANT_PATTERN_MATCHING]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantPatternMatching {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if let ExprKind::Match(ref op, ref arms, ref match_source) = expr.node {
+            match match_source {
+                MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
+                MatchSource::IfLetDesugar { .. } => find_sugg_for_if_let(cx, expr, op, arms),
+                _ => return,
+            }
+        }
+    }
+}
+
+fn find_sugg_for_if_let<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, op: &P<Expr>, arms: &HirVec<Arm>) {
+    if arms[0].pats.len() == 1 {
+        let good_method = match arms[0].pats[0].node {
+            PatKind::TupleStruct(ref path, ref patterns, _) if patterns.len() == 1 => {
+                if let PatKind::Wild = patterns[0].node {
+                    if match_qpath(path, &*paths::RESULT_OK) {
+                        "is_ok()"
+                    } else if match_qpath(path, &*paths::RESULT_ERR) {
+                        "is_err()"
+                    } else if match_qpath(path, &*paths::OPTION_SOME) {
+                        "is_some()"
+                    } else {
+                        return;
+                    }
+                } else {
+                    return;
+                }
+            },
+
+            PatKind::Path(ref path) if match_qpath(path, &*paths::OPTION_NONE) => "is_none()",
+
+            _ => return,
+        };
+
+        span_lint_and_then(
+            cx,
+            REDUNDANT_PATTERN_MATCHING,
+            arms[0].pats[0].span,
+            &format!("redundant pattern matching, consider using `{}`", good_method),
+            |db| {
+                let span = expr.span.to(op.span);
+                db.span_suggestion(
+                    span,
+                    "try this",
+                    format!("if {}.{}", snippet(cx, op.span, "_"), good_method),
+                    Applicability::MachineApplicable, // snippet
+                );
+            },
+        );
+    } else {
+        return;
+    }
+}
+
+fn find_sugg_for_match<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, op: &P<Expr>, arms: &HirVec<Arm>) {
+    if arms.len() == 2 {
+        let node_pair = (&arms[0].pats[0].node, &arms[1].pats[0].node);
+
+        let found_good_method = match node_pair {
+            (
+                PatKind::TupleStruct(ref path_left, ref patterns_left, _),
+                PatKind::TupleStruct(ref path_right, ref patterns_right, _),
+            ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
+                if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].node, &patterns_right[0].node) {
+                    find_good_method_for_match(
+                        arms,
+                        path_left,
+                        path_right,
+                        &*paths::RESULT_OK,
+                        &*paths::RESULT_ERR,
+                        "is_ok()",
+                        "is_err()",
+                    )
+                } else {
+                    None
+                }
+            },
+            (PatKind::TupleStruct(ref path_left, ref patterns, _), PatKind::Path(ref path_right))
+            | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, ref patterns, _))
+                if patterns.len() == 1 =>
+            {
+                if let PatKind::Wild = patterns[0].node {
+                    find_good_method_for_match(
+                        arms,
+                        path_left,
+                        path_right,
+                        &*paths::OPTION_SOME,
+                        &*paths::OPTION_NONE,
+                        "is_some()",
+                        "is_none()",
+                    )
+                } else {
+                    None
+                }
+            },
+            _ => None,
+        };
+
+        if let Some(good_method) = found_good_method {
+            span_lint_and_then(
+                cx,
+                REDUNDANT_PATTERN_MATCHING,
+                expr.span,
+                &format!("redundant pattern matching, consider using `{}`", good_method),
+                |db| {
+                    let span = expr.span.to(op.span);
+                    db.span_suggestion(
+                        span,
+                        "try this",
+                        format!("{}.{}", snippet(cx, op.span, "_"), good_method),
+                        Applicability::MachineApplicable, // snippet
+                    );
+                },
+            );
+        }
+    } else {
+        return;
+    }
+}
+
+fn find_good_method_for_match<'a>(
+    arms: &HirVec<Arm>,
+    path_left: &QPath,
+    path_right: &QPath,
+    expected_left: &[Symbol],
+    expected_right: &[Symbol],
+    should_be_left: &'a str,
+    should_be_right: &'a str,
+) -> Option<&'a str> {
+    let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) {
+        (&(*arms[0].body).node, &(*arms[1].body).node)
+    } else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) {
+        (&(*arms[1].body).node, &(*arms[0].body).node)
+    } else {
+        return None;
+    };
+
+    match body_node_pair {
+        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            _ => None,
+        },
+        _ => None,
+    }
+}
index f349f46d926e31987f2f8a024c4584e69a1e1424..2ee00a2f103470f7d92f8d926ae3ac53ad08b02f 100644 (file)
@@ -1,35 +1,30 @@
-use syntax::ast::{Expr, ExprKind, UnOp};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{snippet_with_applicability, span_lint_and_sugg};
 use if_chain::if_chain;
-use crate::utils::{snippet, span_lint_and_sugg};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::{Expr, ExprKind, UnOp};
 
-/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
-///
-/// **Why is this bad?** Immediately dereferencing a reference is no-op and
-/// makes the code less clear.
-///
-/// **Known problems:** Multiple dereference/addrof pairs are not handled so
-/// the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
-///
-/// **Example:**
-/// ```rust
-/// let a = f(*&mut b);
-/// let c = *&d;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
+    ///
+    /// **Why is this bad?** Immediately dereferencing a reference is no-op and
+    /// makes the code less clear.
+    ///
+    /// **Known problems:** Multiple dereference/addrof pairs are not handled so
+    /// the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let a = f(*&mut b);
+    /// let c = *&d;
+    /// ```
     pub DEREF_ADDROF,
     complexity,
     "use of `*&` or `*&mut` in an expression"
 }
 
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DEREF_ADDROF)
-    }
-}
+declare_lint_pass!(DerefAddrOf => [DEREF_ADDROF]);
 
 fn without_parens(mut e: &Expr) -> &Expr {
     while let ExprKind::Paren(ref child_e) = e.node {
@@ -38,69 +33,63 @@ fn without_parens(mut e: &Expr) -> &Expr {
     e
 }
 
-impl EarlyLintPass for Pass {
+impl EarlyLintPass for DerefAddrOf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
         if_chain! {
             if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node;
             if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node;
             then {
+                let mut applicability = Applicability::MachineApplicable;
                 span_lint_and_sugg(
                     cx,
                     DEREF_ADDROF,
                     e.span,
                     "immediately dereferencing a reference",
                     "try this",
-                    format!("{}", snippet(cx, addrof_target.span, "_")),
+                    format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)),
+                    applicability,
                 );
             }
         }
     }
 }
 
-/// **What it does:** Checks for references in expressions that use
-/// auto dereference.
-///
-/// **Why is this bad?** The reference is a no-op and is automatically
-/// dereferenced by the compiler and makes the code less clear.
-///
-/// **Example:**
-/// ```rust
-/// struct Point(u32, u32);
-/// let point = Foo(30, 20);
-/// let x = (&point).x;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for references in expressions that use
+    /// auto dereference.
+    ///
+    /// **Why is this bad?** The reference is a no-op and is automatically
+    /// dereferenced by the compiler and makes the code less clear.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct Point(u32, u32);
+    /// let point = Foo(30, 20);
+    /// let x = (&point).x;
+    /// ```
     pub REF_IN_DEREF,
     complexity,
     "Use of reference in auto dereference expression."
 }
 
-pub struct DerefPass;
-
-impl LintPass for DerefPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(REF_IN_DEREF)
-    }
-}
+declare_lint_pass!(RefInDeref => [REF_IN_DEREF]);
 
-impl EarlyLintPass for DerefPass {
+impl EarlyLintPass for RefInDeref {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
         if_chain! {
-            if let ExprKind::Field(ref object, ref field_name) = e.node;
+            if let ExprKind::Field(ref object, _) = e.node;
             if let ExprKind::Paren(ref parened) = object.node;
             if let ExprKind::AddrOf(_, ref inner) = parened.node;
             then {
+                let mut applicability = Applicability::MachineApplicable;
                 span_lint_and_sugg(
                     cx,
                     REF_IN_DEREF,
                     object.span,
                     "Creating a reference that is immediately dereferenced.",
                     "try this",
-                    format!(
-                        "{}.{}",
-                        snippet(cx, inner.span, "_"),
-                        snippet(cx, field_name.span, "_")
-                    )
+                    snippet_with_applicability(cx, inner.span, "_", &mut applicability).to_string(),
+                    applicability,
                 );
             }
         }
index 39b7888dcc609b95dfc844e132d610ceceedbfcd..59b1cc016712ce6e5e1bbe6e42225cfd1a77d099 100644 (file)
@@ -1,83 +1,81 @@
+use crate::consts::{constant, Constant};
+use crate::utils::sym;
+use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_help_and_lint, span_lint};
+use if_chain::if_chain;
 use regex_syntax;
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use std::collections::HashSet;
-use syntax::ast::{LitKind, NodeId, StrStyle};
-use syntax::codemap::{BytePos, Span};
-use crate::utils::{is_expn_of, match_def_path, match_type, opt_def_id, paths, span_help_and_lint, span_lint};
-use crate::consts::{constant, Constant};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_data_structures::fx::FxHashSet;
+use std::convert::TryFrom;
+use syntax::ast::{LitKind, StrStyle};
+use syntax::source_map::{BytePos, Span};
 
-/// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
-/// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct
-/// regex syntax.
-///
-/// **Why is this bad?** This will lead to a runtime panic.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// Regex::new("|")
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation
+    /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct
+    /// regex syntax.
+    ///
+    /// **Why is this bad?** This will lead to a runtime panic.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// Regex::new("|")
+    /// ```
     pub INVALID_REGEX,
     correctness,
     "invalid regular expressions"
 }
 
-/// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex)
-/// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`).
-///
-/// **Why is this bad?** Matching the regex can likely be replaced by `==` or
-/// `str::starts_with`, `str::ends_with` or `std::contains` or other `str`
-/// methods.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// Regex::new("^foobar")
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex)
+    /// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`).
+    ///
+    /// **Why is this bad?** Matching the regex can likely be replaced by `==` or
+    /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str`
+    /// methods.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// Regex::new("^foobar")
+    /// ```
     pub TRIVIAL_REGEX,
     style,
     "trivial regular expressions"
 }
 
-/// **What it does:** Checks for usage of `regex!(_)` which (as of now) is
-/// usually slower than `Regex::new(_)` unless called in a loop (which is a bad
-/// idea anyway).
-///
-/// **Why is this bad?** Performance, at least for now. The macro version is
-/// likely to catch up long-term, but for now the dynamic version is faster.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// regex!("foo|bar")
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `regex!(_)` which (as of now) is
+    /// usually slower than `Regex::new(_)` unless called in a loop (which is a bad
+    /// idea anyway).
+    ///
+    /// **Why is this bad?** Performance, at least for now. The macro version is
+    /// likely to catch up long-term, but for now the dynamic version is faster.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// regex!("foo|bar")
+    /// ```
     pub REGEX_MACRO,
     style,
     "use of `regex!(_)` instead of `Regex::new(_)`"
 }
 
 #[derive(Clone, Default)]
-pub struct Pass {
-    spans: HashSet<Span>,
-    last: Option<NodeId>,
+pub struct Regex {
+    spans: FxHashSet<Span>,
+    last: Option<HirId>,
 }
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX)
-    }
-}
+impl_lint_pass!(Regex => [INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Regex {
     fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx Crate) {
         self.spans.clear();
     }
@@ -86,8 +84,8 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
         if_chain! {
             if self.last.is_none();
             if let Some(ref expr) = block.expr;
-            if match_type(cx, cx.tables.expr_ty(expr), &paths::REGEX);
-            if let Some(span) = is_expn_of(expr.span, "regex");
+            if match_type(cx, cx.tables.expr_ty(expr), &*paths::REGEX);
+            if let Some(span) = is_expn_of(expr.span, *sym::regex);
             then {
                 if !self.spans.contains(&span) {
                     span_lint(cx,
@@ -97,13 +95,13 @@ fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
                               Please use `Regex::new(_)`, which is faster for now.");
                     self.spans.insert(span);
                 }
-                self.last = Some(block.id);
+                self.last = Some(block.hir_id);
             }
         }
     }
 
     fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, block: &'tcx Block) {
-        if self.last.map_or(false, |id| block.id == id) {
+        if self.last.map_or(false, |id| block.hir_id == id) {
             self.last = None;
         }
     }
@@ -113,17 +111,17 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             if let ExprKind::Call(ref fun, ref args) = expr.node;
             if let ExprKind::Path(ref qpath) = fun.node;
             if args.len() == 1;
-            if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, fun.hir_id));
+            if let Some(def_id) = cx.tables.qpath_res(qpath, fun.hir_id).opt_def_id();
             then {
-                if match_def_path(cx.tcx, def_id, &paths::REGEX_NEW) ||
-                   match_def_path(cx.tcx, def_id, &paths::REGEX_BUILDER_NEW) {
+                if match_def_path(cx, def_id, &*paths::REGEX_NEW) ||
+                   match_def_path(cx, def_id, &*paths::REGEX_BUILDER_NEW) {
                     check_regex(cx, &args[0], true);
-                } else if match_def_path(cx.tcx, def_id, &paths::REGEX_BYTES_NEW) ||
-                   match_def_path(cx.tcx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
+                } else if match_def_path(cx, def_id, &*paths::REGEX_BYTES_NEW) ||
+                   match_def_path(cx, def_id, &*paths::REGEX_BYTES_BUILDER_NEW) {
                     check_regex(cx, &args[0], false);
-                } else if match_def_path(cx.tcx, def_id, &paths::REGEX_SET_NEW) {
+                } else if match_def_path(cx, def_id, &*paths::REGEX_SET_NEW) {
                     check_set(cx, &args[0], true);
-                } else if match_def_path(cx.tcx, def_id, &paths::REGEX_BYTES_SET_NEW) {
+                } else if match_def_path(cx, def_id, &*paths::REGEX_BYTES_SET_NEW) {
                     check_set(cx, &args[0], false);
                 }
             }
@@ -131,10 +129,11 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
+#[allow(clippy::cast_possible_truncation)] // truncation very unlikely here
 fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u16) -> Span {
     let offset = u32::from(offset);
-    let end = base.lo() + BytePos(c.end.offset as u32 + offset);
-    let start = base.lo() + BytePos(c.start.offset as u32 + offset);
+    let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
+    let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset);
     assert!(start <= end);
     Span::new(start, end, base.ctxt())
 }
@@ -147,28 +146,37 @@ fn const_str<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Stri
 }
 
 fn is_trivial_regex(s: &regex_syntax::hir::Hir) -> Option<&'static str> {
-    use regex_syntax::hir::HirKind::*;
     use regex_syntax::hir::Anchor::*;
+    use regex_syntax::hir::HirKind::*;
 
-    let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| match *e.kind() {
-        Literal(_) => true,
-        _ => false,
-    });
+    let is_literal = |e: &[regex_syntax::hir::Hir]| {
+        e.iter().all(|e| match *e.kind() {
+            Literal(_) => true,
+            _ => false,
+        })
+    };
 
     match *s.kind() {
-        Empty |
-        Anchor(_) => Some("the regex is unlikely to be useful as it is"),
+        Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"),
         Literal(_) => Some("consider using `str::contains`"),
-        Alternation(ref exprs) => if exprs.iter().all(|e| e.kind().is_empty()) {
-            Some("the regex is unlikely to be useful as it is")
-        } else {
-            None
+        Alternation(ref exprs) => {
+            if exprs.iter().all(|e| e.kind().is_empty()) {
+                Some("the regex is unlikely to be useful as it is")
+            } else {
+                None
+            }
         },
         Concat(ref exprs) => match (exprs[0].kind(), exprs[exprs.len() - 1].kind()) {
-            (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => Some("consider using `str::is_empty`"),
-            (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => Some("consider using `==` on `str`s"),
+            (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => {
+                Some("consider using `str::is_empty`")
+            },
+            (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => {
+                Some("consider using `==` on `str`s")
+            },
             (&Anchor(StartText), &Literal(_)) if is_literal(&exprs[1..]) => Some("consider using `str::starts_with`"),
-            (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => Some("consider using `str::ends_with`"),
+            (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => {
+                Some("consider using `str::ends_with`")
+            },
             _ if is_literal(exprs) => Some("consider using `str::contains`"),
             _ => None,
         },
@@ -199,14 +207,10 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: boo
             let r = &r.as_str();
             let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 };
             match parser.parse(r) {
-                Ok(r) => if let Some(repl) = is_trivial_regex(&r) {
-                    span_help_and_lint(
-                        cx,
-                        TRIVIAL_REGEX,
-                        expr.span,
-                        "trivial regex",
-                        repl,
-                    );
+                Ok(r) => {
+                    if let Some(repl) = is_trivial_regex(&r) {
+                        span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, "trivial regex", repl);
+                    }
                 },
                 Err(regex_syntax::Error::Parse(e)) => {
                     span_lint(
@@ -225,25 +229,16 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: boo
                     );
                 },
                 Err(e) => {
-                    span_lint(
-                        cx,
-                        INVALID_REGEX,
-                        expr.span,
-                        &format!("regex syntax error: {}", e),
-                    );
+                    span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e));
                 },
             }
         }
     } else if let Some(r) = const_str(cx, expr) {
         match parser.parse(&r) {
-            Ok(r) => if let Some(repl) = is_trivial_regex(&r) {
-                span_help_and_lint(
-                    cx,
-                    TRIVIAL_REGEX,
-                    expr.span,
-                    "trivial regex",
-                    repl,
-                );
+            Ok(r) => {
+                if let Some(repl) = is_trivial_regex(&r) {
+                    span_help_and_lint(cx, TRIVIAL_REGEX, expr.span, "trivial regex", repl);
+                }
             },
             Err(regex_syntax::Error::Parse(e)) => {
                 span_lint(
@@ -262,12 +257,7 @@ fn check_regex<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, utf8: boo
                 );
             },
             Err(e) => {
-                span_lint(
-                    cx,
-                    INVALID_REGEX,
-                    expr.span,
-                    &format!("regex syntax error: {}", e),
-                );
+                span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {}", e));
             },
         }
     }
index b9a4c6ebb1958d5927bcc4e73920a1b85e920d2b..80ea39a301c044fede73ba69bb932b1570322386 100644 (file)
@@ -1,49 +1,47 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{match_def_path, span_lint_and_sugg};
 use if_chain::if_chain;
+use lazy_static::lazy_static;
 use rustc::hir;
-use rustc::hir::def::Def;
-use crate::utils::{match_def_path, span_lint_and_sugg};
+use rustc::hir::def::{DefKind, Res};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::symbol::Symbol;
 
-/// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and
-/// `uX/iX::MIN/MAX`.
-///
-/// **Why is this bad?** `const fn`s exist
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// static FOO: AtomicIsize = ATOMIC_ISIZE_INIT;
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// static FOO: AtomicIsize = AtomicIsize::new(0);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and
+    /// `uX/iX::MIN/MAX`.
+    ///
+    /// **Why is this bad?** `const fn`s exist
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// static FOO: AtomicIsize = ATOMIC_ISIZE_INIT;
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// static FOO: AtomicIsize = AtomicIsize::new(0);
+    /// ```
     pub REPLACE_CONSTS,
     pedantic,
     "Lint usages of standard library `const`s that could be replaced by `const fn`s"
 }
 
-pub struct ReplaceConsts;
-
-impl LintPass for ReplaceConsts {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(REPLACE_CONSTS)
-    }
-}
+declare_lint_pass!(ReplaceConsts => [REPLACE_CONSTS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
         if_chain! {
             if let hir::ExprKind::Path(ref qp) = expr.node;
-            if let Def::Const(def_id) = cx.tables.qpath_def(qp, expr.hir_id);
+            if let Res::Def(DefKind::Const, def_id) = cx.tables.qpath_res(qp, expr.hir_id);
             then {
-                for &(const_path, repl_snip) in REPLACEMENTS {
-                    if match_def_path(cx.tcx, def_id, const_path) {
+                for (const_path, repl_snip) in REPLACEMENTS.iter() {
+                    if match_def_path(cx, def_id, const_path) {
                         span_lint_and_sugg(
                             cx,
                             REPLACE_CONSTS,
@@ -51,6 +49,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                             &format!("using `{}`", const_path.last().expect("empty path")),
                             "try this",
                             repl_snip.to_string(),
+                            Applicability::MachineApplicable,
                         );
                         return;
                     }
@@ -60,45 +59,35 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
     }
 }
 
-const REPLACEMENTS: &[(&[&str], &str)] = &[
+lazy_static! {
+static ref REPLACEMENTS: [([Symbol; 3], &'static str); 25] = [
     // Once
-    (&["core", "sync",  "ONCE_INIT"], "Once::new()"),
-    // Atomic
-    (&["core", "sync", "atomic", "ATOMIC_BOOL_INIT"],  "AtomicBool::new(false)"),
-    (&["core", "sync", "atomic", "ATOMIC_ISIZE_INIT"], "AtomicIsize::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_I8_INIT"],    "AtomicI8::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_I16_INIT"],   "AtomicI16::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_I32_INIT"],   "AtomicI32::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_I64_INIT"],   "AtomicI64::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_USIZE_INIT"], "AtomicUsize::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_U8_INIT"],    "AtomicU8::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_U16_INIT"],   "AtomicU16::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_U32_INIT"],   "AtomicU32::new(0)"),
-    (&["core", "sync", "atomic", "ATOMIC_U64_INIT"],   "AtomicU64::new(0)"),
+    ([*sym::core, *sym::sync, *sym::ONCE_INIT], "Once::new()"),
     // Min
-    (&["core", "isize", "MIN"], "isize::min_value()"),
-    (&["core", "i8",    "MIN"], "i8::min_value()"),
-    (&["core", "i16",   "MIN"], "i16::min_value()"),
-    (&["core", "i32",   "MIN"], "i32::min_value()"),
-    (&["core", "i64",   "MIN"], "i64::min_value()"),
-    (&["core", "i128",  "MIN"], "i128::min_value()"),
-    (&["core", "usize", "MIN"], "usize::min_value()"),
-    (&["core", "u8",    "MIN"], "u8::min_value()"),
-    (&["core", "u16",   "MIN"], "u16::min_value()"),
-    (&["core", "u32",   "MIN"], "u32::min_value()"),
-    (&["core", "u64",   "MIN"], "u64::min_value()"),
-    (&["core", "u128",  "MIN"], "u128::min_value()"),
+    ([*sym::core, *sym::isize, *sym::MIN], "isize::min_value()"),
+    ([*sym::core, *sym::i8, *sym::MIN], "i8::min_value()"),
+    ([*sym::core, *sym::i16, *sym::MIN], "i16::min_value()"),
+    ([*sym::core, *sym::i32, *sym::MIN], "i32::min_value()"),
+    ([*sym::core, *sym::i64, *sym::MIN], "i64::min_value()"),
+    ([*sym::core, *sym::i128, *sym::MIN], "i128::min_value()"),
+    ([*sym::core, *sym::usize, *sym::MIN], "usize::min_value()"),
+    ([*sym::core, *sym::u8, *sym::MIN], "u8::min_value()"),
+    ([*sym::core, *sym::u16, *sym::MIN], "u16::min_value()"),
+    ([*sym::core, *sym::u32, *sym::MIN], "u32::min_value()"),
+    ([*sym::core, *sym::u64, *sym::MIN], "u64::min_value()"),
+    ([*sym::core, *sym::u128, *sym::MIN], "u128::min_value()"),
     // Max
-    (&["core", "isize", "MAX"], "isize::max_value()"),
-    (&["core", "i8",    "MAX"], "i8::max_value()"),
-    (&["core", "i16",   "MAX"], "i16::max_value()"),
-    (&["core", "i32",   "MAX"], "i32::max_value()"),
-    (&["core", "i64",   "MAX"], "i64::max_value()"),
-    (&["core", "i128",  "MAX"], "i128::max_value()"),
-    (&["core", "usize", "MAX"], "usize::max_value()"),
-    (&["core", "u8",    "MAX"], "u8::max_value()"),
-    (&["core", "u16",   "MAX"], "u16::max_value()"),
-    (&["core", "u32",   "MAX"], "u32::max_value()"),
-    (&["core", "u64",   "MAX"], "u64::max_value()"),
-    (&["core", "u128",  "MAX"], "u128::max_value()"),
+    ([*sym::core, *sym::isize, *sym::MAX], "isize::max_value()"),
+    ([*sym::core, *sym::i8, *sym::MAX], "i8::max_value()"),
+    ([*sym::core, *sym::i16, *sym::MAX], "i16::max_value()"),
+    ([*sym::core, *sym::i32, *sym::MAX], "i32::max_value()"),
+    ([*sym::core, *sym::i64, *sym::MAX], "i64::max_value()"),
+    ([*sym::core, *sym::i128, *sym::MAX], "i128::max_value()"),
+    ([*sym::core, *sym::usize, *sym::MAX], "usize::max_value()"),
+    ([*sym::core, *sym::u8, *sym::MAX], "u8::max_value()"),
+    ([*sym::core, *sym::u16, *sym::MAX], "u16::max_value()"),
+    ([*sym::core, *sym::u32, *sym::MAX], "u32::max_value()"),
+    ([*sym::core, *sym::u64, *sym::MAX], "u64::max_value()"),
+    ([*sym::core, *sym::u128, *sym::MAX], "u128::max_value()"),
 ];
+}
index 0ede1bc972745e7dba3e11b07a31f35d93f4a76c..0764a96e263e446b7886fd50604f6ccd72adc1fb 100644 (file)
@@ -1,53 +1,92 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
+use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use syntax::ast;
-use syntax::codemap::Span;
+use syntax::source_map::Span;
 use syntax::visit::FnKind;
+use syntax_pos::BytePos;
+
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint};
 
-use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_then, span_note_and_lint};
-
-/// **What it does:** Checks for return statements at the end of a block.
-///
-/// **Why is this bad?** Removing the `return` and semicolon will make the code
-/// more rusty.
-///
-/// **Known problems:** If the computation returning the value borrows a local
-/// variable, removing the `return` may run afoul of the borrow checker.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(x: usize) { return x; }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for return statements at the end of a block.
+    ///
+    /// **Why is this bad?** Removing the `return` and semicolon will make the code
+    /// more rusty.
+    ///
+    /// **Known problems:** If the computation returning the value borrows a local
+    /// variable, removing the `return` may run afoul of the borrow checker.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(x: usize) -> usize {
+    ///     return x;
+    /// }
+    /// ```
+    /// simplify to
+    /// ```rust
+    /// fn foo(x: usize) -> usize {
+    ///     x
+    /// }
+    /// ```
     pub NEEDLESS_RETURN,
     style,
     "using a return statement like `return expr;` where an expression would suffice"
 }
 
-/// **What it does:** Checks for `let`-bindings, which are subsequently
-/// returned.
-///
-/// **Why is this bad?** It is just extraneous code. Remove it to make your code
-/// more rusty.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// { let x = ..; x }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `let`-bindings, which are subsequently
+    /// returned.
+    ///
+    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
+    /// more rusty.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo() -> String {
+    ///     let x = String::new();
+    ///     x
+    /// }
+    /// ```
+    /// instead, use
+    /// ```
+    /// fn foo() -> String {
+    ///     String::new()
+    /// }
+    /// ```
     pub LET_AND_RETURN,
     style,
-    "creating a let-binding and then immediately returning it like `let x = expr; x` at \
-     the end of a block"
+    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
 }
 
-#[derive(Copy, Clone)]
-pub struct ReturnPass;
+declare_clippy_lint! {
+    /// **What it does:** Checks for unit (`()`) expressions that can be removed.
+    ///
+    /// **Why is this bad?** Such expressions add no value, but can make the code
+    /// less readable. Depending on formatting they can make a `break` or `return`
+    /// statement look like a function call.
+    ///
+    /// **Known problems:** The lint currently misses unit return types in types,
+    /// e.g., the `F` in `fn generic_unit<F: Fn() -> ()>(f: F) { .. }`.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn return_unit() -> () {
+    ///     ()
+    /// }
+    /// ```
+    pub UNUSED_UNIT,
+    style,
+    "needless unit expression"
+}
 
-impl ReturnPass {
+declare_lint_pass!(Return => [NEEDLESS_RETURN, LET_AND_RETURN, UNUSED_UNIT]);
+
+impl Return {
     // Check the final stmt or expr in a block for unnecessary return.
     fn check_block_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
         if let Some(stmt) = block.stmts.last() {
@@ -82,20 +121,27 @@ fn check_final_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr, span: Op
                 self.check_final_expr(cx, elsexpr, None);
             },
             // a match expr, check all arms
-            ast::ExprKind::Match(_, ref arms) => for arm in arms {
-                self.check_final_expr(cx, &arm.body, Some(arm.body.span));
+            ast::ExprKind::Match(_, ref arms) => {
+                for arm in arms {
+                    self.check_final_expr(cx, &arm.body, Some(arm.body.span));
+                }
             },
             _ => (),
         }
     }
 
     fn emit_return_lint(&mut self, cx: &EarlyContext<'_>, ret_span: Span, inner_span: Span) {
-        if in_external_macro(cx.sess(), inner_span) || in_macro(inner_span) {
+        if in_external_macro(cx.sess(), inner_span) || in_macro_or_desugar(inner_span) {
             return;
         }
         span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded return statement", |db| {
             if let Some(snippet) = snippet_opt(cx, inner_span) {
-                db.span_suggestion(ret_span, "remove `return` as shown", snippet);
+                db.span_suggestion(
+                    ret_span,
+                    "remove `return` as shown",
+                    snippet,
+                    Applicability::MachineApplicable,
+                );
             }
         });
     }
@@ -112,11 +158,11 @@ fn check_let_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
             if let ast::StmtKind::Local(ref local) = stmt.node;
             // don't lint in the presence of type inference
             if local.ty.is_none();
-            if !local.attrs.iter().any(attr_is_cfg);
+            if local.attrs.is_empty();
             if let Some(ref initexpr) = local.init;
             if let ast::PatKind::Ident(_, ident, _) = local.pat.node;
             if let ast::ExprKind::Path(_, ref path) = retexpr.node;
-            if match_path_ast(path, &[&ident.as_str()]);
+            if match_path_ast(path, &[ident.name]);
             if !in_external_macro(cx.sess(), initexpr.span);
             then {
                     span_note_and_lint(cx,
@@ -131,25 +177,95 @@ fn check_let_return(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
     }
 }
 
-impl LintPass for ReturnPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(NEEDLESS_RETURN, LET_AND_RETURN)
-    }
-}
-
-impl EarlyLintPass for ReturnPass {
-    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: &ast::FnDecl, _: Span, _: ast::NodeId) {
+impl EarlyLintPass for Return {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, decl: &ast::FnDecl, span: Span, _: ast::NodeId) {
         match kind {
             FnKind::ItemFn(.., block) | FnKind::Method(.., block) => self.check_block_return(cx, block),
             FnKind::Closure(body) => self.check_final_expr(cx, body, Some(body.span)),
         }
+        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);
+            then {
+                let (rspan, appl) = if let Ok(fn_source) =
+                        cx.sess().source_map()
+                                 .span_to_snippet(span.with_hi(ty.span.hi())) {
+                    if let Some(rpos) = fn_source.rfind("->") {
+                        #[allow(clippy::cast_possible_truncation)]
+                        (ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
+                            Applicability::MachineApplicable)
+                    } else {
+                        (ty.span, Applicability::MaybeIncorrect)
+                    }
+                } else {
+                    (ty.span, Applicability::MaybeIncorrect)
+                };
+                span_lint_and_then(cx, UNUSED_UNIT, rspan, "unneeded unit return type", |db| {
+                    db.span_suggestion(
+                        rspan,
+                        "remove the `-> ()`",
+                        String::new(),
+                        appl,
+                    );
+                });
+            }
+        }
     }
 
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
         self.check_let_return(cx, block);
+        if_chain! {
+            if let Some(ref stmt) = block.stmts.last();
+            if let ast::StmtKind::Expr(ref expr) = stmt.node;
+            if is_unit_expr(expr) && !in_macro_or_desugar(expr.span);
+            then {
+                let sp = expr.span;
+                span_lint_and_then(cx, UNUSED_UNIT, sp, "unneeded unit expression", |db| {
+                    db.span_suggestion(
+                        sp,
+                        "remove the final `()`",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    );
+                });
+            }
+        }
+    }
+
+    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) {
+                    span_lint_and_then(cx, UNUSED_UNIT, expr.span, "unneeded `()`", |db| {
+                        db.span_suggestion(
+                            expr.span,
+                            "remove the `()`",
+                            String::new(),
+                            Applicability::MachineApplicable,
+                        );
+                    });
+                }
+            },
+            _ => (),
+        }
     }
 }
 
 fn attr_is_cfg(attr: &ast::Attribute) -> bool {
-    attr.meta_item_list().is_some() && attr.name() == "cfg"
+    attr.meta_item_list().is_some() && attr.check_name(*sym::cfg)
+}
+
+// get the def site
+fn get_def(span: Span) -> Option<Span> {
+    span.ctxt().outer().expn_info().and_then(|info| info.def_site)
+}
+
+// is this expr a `()` unit?
+fn is_unit_expr(expr: &ast::Expr) -> bool {
+    if let ast::ExprKind::Tup(ref vals) = expr.node {
+        vals.is_empty()
+    } else {
+        false
+    }
 }
index ce326ea72ca81619ac01882465453eafa3f4495e..37eb2dd49426097e120324464c64e9ba4130764e 100644 (file)
@@ -1,38 +1,30 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
 use crate::utils::{get_trait_def_id, paths, span_lint};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for mis-uses of the serde API.
-///
-/// **Why is this bad?** Serde is very finnicky about how its API should be
-/// used, but the type system can't be used to enforce it (yet?).
-///
-/// **Known problems:** None.
-///
-/// **Example:** Implementing `Visitor::visit_string` but not
-/// `Visitor::visit_str`.
 declare_clippy_lint! {
+    /// **What it does:** Checks for mis-uses of the serde API.
+    ///
+    /// **Why is this bad?** Serde is very finnicky about how its API should be
+    /// used, but the type system can't be used to enforce it (yet?).
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:** Implementing `Visitor::visit_string` but not
+    /// `Visitor::visit_str`.
     pub SERDE_API_MISUSE,
     correctness,
     "various things that will negatively affect your serde experience"
 }
 
+declare_lint_pass!(SerdeAPI => [SERDE_API_MISUSE]);
 
-#[derive(Copy, Clone)]
-pub struct Serde;
-
-impl LintPass for Serde {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(SERDE_API_MISUSE)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Serde {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SerdeAPI {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, ref items) = item.node {
-            let did = trait_ref.path.def.def_id();
-            if let Some(visit_did) = get_trait_def_id(cx, &paths::SERDE_DE_VISITOR) {
+            let did = trait_ref.path.res.def_id();
+            if let Some(visit_did) = get_trait_def_id(cx, &*paths::SERDE_DE_VISITOR) {
                 if did == visit_did {
                     let mut seen_str = None;
                     let mut seen_string = None;
index aab578d634453f62d06d7128dc269ff8533dfee1..2d85189d111da2dd397696fe4dd0b7676fd5398b 100644 (file)
@@ -1,86 +1,83 @@
 use crate::reexport::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
+use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then};
 use rustc::hir::intravisit::FnKind;
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
-use syntax::codemap::Span;
-use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for bindings that shadow other bindings already in
-/// scope, while just changing reference level or mutability.
-///
-/// **Why is this bad?** Not much, in fact it's a very common pattern in Rust
-/// code. Still, some may opt to avoid it in their code base, they can set this
-/// lint to `Warn`.
-///
-/// **Known problems:** This lint, as the other shadowing related lints,
-/// currently only catches very simple patterns.
-///
-/// **Example:**
-/// ```rust
-/// let x = &x;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for bindings that shadow other bindings already in
+    /// scope, while just changing reference level or mutability.
+    ///
+    /// **Why is this bad?** Not much, in fact it's a very common pattern in Rust
+    /// code. Still, some may opt to avoid it in their code base, they can set this
+    /// lint to `Warn`.
+    ///
+    /// **Known problems:** This lint, as the other shadowing related lints,
+    /// currently only catches very simple patterns.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = &x;
+    /// ```
     pub SHADOW_SAME,
     restriction,
-    "rebinding a name to itself, e.g. `let mut x = &mut x`"
+    "rebinding a name to itself, e.g., `let mut x = &mut x`"
 }
 
-/// **What it does:** Checks for bindings that shadow other bindings already in
-/// scope, while reusing the original value.
-///
-/// **Why is this bad?** Not too much, in fact it's a common pattern in Rust
-/// code. Still, some argue that name shadowing like this hurts readability,
-/// because a value may be bound to different things depending on position in
-/// the code.
-///
-/// **Known problems:** This lint, as the other shadowing related lints,
-/// currently only catches very simple patterns.
-///
-/// **Example:**
-/// ```rust
-/// let x = x + 1;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for bindings that shadow other bindings already in
+    /// scope, while reusing the original value.
+    ///
+    /// **Why is this bad?** Not too much, in fact it's a common pattern in Rust
+    /// code. Still, some argue that name shadowing like this hurts readability,
+    /// because a value may be bound to different things depending on position in
+    /// the code.
+    ///
+    /// **Known problems:** This lint, as the other shadowing related lints,
+    /// currently only catches very simple patterns.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = x + 1;
+    /// ```
+    /// use different variable name:
+    /// ```rust
+    /// let y = x + 1;
+    /// ```
     pub SHADOW_REUSE,
     restriction,
-    "rebinding a name to an expression that re-uses the original value, e.g. \
-     `let x = x + 1`"
+    "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`"
 }
 
-/// **What it does:** Checks for bindings that shadow other bindings already in
-/// scope, either without a initialization or with one that does not even use
-/// the original value.
-///
-/// **Why is this bad?** Name shadowing can hurt readability, especially in
-/// large code bases, because it is easy to lose track of the active binding at
-/// any place in the code. This can be alleviated by either giving more specific
-/// names to bindings or introducing more scopes to contain the bindings.
-///
-/// **Known problems:** This lint, as the other shadowing related lints,
-/// currently only catches very simple patterns.
-///
-/// **Example:**
-/// ```rust
-/// let x = y; let x = z; // shadows the earlier binding
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for bindings that shadow other bindings already in
+    /// scope, either without a initialization or with one that does not even use
+    /// the original value.
+    ///
+    /// **Why is this bad?** Name shadowing can hurt readability, especially in
+    /// large code bases, because it is easy to lose track of the active binding at
+    /// any place in the code. This can be alleviated by either giving more specific
+    /// names to bindings or introducing more scopes to contain the bindings.
+    ///
+    /// **Known problems:** This lint, as the other shadowing related lints,
+    /// currently only catches very simple patterns.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = y;
+    /// let x = z; // shadows the earlier binding
+    /// ```
     pub SHADOW_UNRELATED,
-    restriction,
+    pedantic,
     "rebinding a name without even using the original value"
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED)
-    }
-}
+declare_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Shadow {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -88,7 +85,7 @@ fn check_fn(
         decl: &'tcx FnDecl,
         body: &'tcx Body,
         _: Span,
-        _: NodeId,
+        _: HirId,
     ) {
         if in_external_macro(cx.sess(), body.value.span) {
             return;
@@ -100,7 +97,7 @@ fn check_fn(
 fn check_fn<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl, body: &'tcx Body) {
     let mut bindings = Vec::new();
     for arg in iter_input_pats(decl, body) {
-        if let PatKind::Binding(_, _, ident, _) = arg.pat.node {
+        if let PatKind::Binding(.., ident, _) = arg.pat.node {
             bindings.push((ident.name, ident.span))
         }
     }
@@ -111,8 +108,9 @@ fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, binding
     let len = bindings.len();
     for stmt in &block.stmts {
         match stmt.node {
-            StmtKind::Decl(ref decl, _) => check_decl(cx, decl, bindings),
-            StmtKind::Expr(ref e, _) | StmtKind::Semi(ref e, _) => check_expr(cx, e, bindings),
+            StmtKind::Local(ref local) => check_local(cx, local, bindings),
+            StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => check_expr(cx, e, bindings),
+            StmtKind::Item(..) => {},
         }
     }
     if let Some(ref o) = block.expr {
@@ -121,37 +119,35 @@ fn check_block<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, block: &'tcx Block, binding
     bindings.truncate(len);
 }
 
-fn check_decl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl, bindings: &mut Vec<(Name, Span)>) {
-    if in_external_macro(cx.sess(), decl.span) {
+fn check_local<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, local: &'tcx Local, bindings: &mut Vec<(Name, Span)>) {
+    if in_external_macro(cx.sess(), local.span) {
         return;
     }
-    if higher::is_from_for_desugar(decl) {
+    if higher::is_from_for_desugar(local) {
         return;
     }
-    if let DeclKind::Local(ref local) = decl.node {
-        let Local {
-            ref pat,
-            ref ty,
-            ref init,
-            span,
-            ..
-        } = **local;
-        if let Some(ref t) = *ty {
-            check_ty(cx, t, bindings)
-        }
-        if let Some(ref o) = *init {
-            check_expr(cx, o, bindings);
-            check_pat(cx, pat, Some(o), span, bindings);
-        } else {
-            check_pat(cx, pat, None, span, bindings);
-        }
+    let Local {
+        ref pat,
+        ref ty,
+        ref init,
+        span,
+        ..
+    } = *local;
+    if let Some(ref t) = *ty {
+        check_ty(cx, t, bindings)
+    }
+    if let Some(ref o) = *init {
+        check_expr(cx, o, bindings);
+        check_pat(cx, pat, Some(o), span, bindings);
+    } else {
+        check_pat(cx, pat, None, span, bindings);
     }
 }
 
 fn is_binding(cx: &LateContext<'_, '_>, pat_id: HirId) -> bool {
-    let var_ty = cx.tables.node_id_to_type(pat_id);
+    let var_ty = cx.tables.node_type(pat_id);
     match var_ty.sty {
-        ty::TyAdt(..) => false,
+        ty::Adt(..) => false,
         _ => true,
     }
 }
@@ -165,7 +161,7 @@ fn check_pat<'a, 'tcx>(
 ) {
     // TODO: match more stuff / destructuring
     match pat.node {
-        PatKind::Binding(_, _, ident, ref inner) => {
+        PatKind::Binding(.., ident, ref inner) => {
             let name = ident.name;
             if is_binding(cx, pat.hir_id) {
                 let mut new_binding = true;
@@ -185,49 +181,54 @@ fn check_pat<'a, 'tcx>(
                 check_pat(cx, p, init, span, bindings);
             }
         },
-        PatKind::Struct(_, ref pfields, _) => if let Some(init_struct) = init {
-            if let ExprKind::Struct(_, ref efields, _) = init_struct.node {
-                for field in pfields {
-                    let name = field.node.ident.name;
-                    let efield = efields
-                        .iter()
-                        .find(|f| f.ident.name == name)
-                        .map(|f| &*f.expr);
-                    check_pat(cx, &field.node.pat, efield, span, bindings);
+        PatKind::Struct(_, ref pfields, _) => {
+            if let Some(init_struct) = init {
+                if let ExprKind::Struct(_, ref efields, _) = init_struct.node {
+                    for field in pfields {
+                        let name = field.node.ident.name;
+                        let efield = efields
+                            .iter()
+                            .find_map(|f| if f.ident.name == name { Some(&*f.expr) } else { None });
+                        check_pat(cx, &field.node.pat, efield, span, bindings);
+                    }
+                } else {
+                    for field in pfields {
+                        check_pat(cx, &field.node.pat, init, span, bindings);
+                    }
                 }
             } else {
                 for field in pfields {
-                    check_pat(cx, &field.node.pat, init, span, bindings);
+                    check_pat(cx, &field.node.pat, None, span, bindings);
                 }
             }
-        } else {
-            for field in pfields {
-                check_pat(cx, &field.node.pat, None, span, bindings);
-            }
         },
-        PatKind::Tuple(ref inner, _) => if let Some(init_tup) = init {
-            if let ExprKind::Tup(ref tup) = init_tup.node {
-                for (i, p) in inner.iter().enumerate() {
-                    check_pat(cx, p, Some(&tup[i]), p.span, bindings);
+        PatKind::Tuple(ref inner, _) => {
+            if let Some(init_tup) = init {
+                if let ExprKind::Tup(ref tup) = init_tup.node {
+                    for (i, p) in inner.iter().enumerate() {
+                        check_pat(cx, p, Some(&tup[i]), p.span, bindings);
+                    }
+                } else {
+                    for p in inner {
+                        check_pat(cx, p, init, span, bindings);
+                    }
                 }
             } else {
                 for p in inner {
-                    check_pat(cx, p, init, span, bindings);
+                    check_pat(cx, p, None, span, bindings);
                 }
             }
-        } else {
-            for p in inner {
-                check_pat(cx, p, None, span, bindings);
-            }
         },
-        PatKind::Box(ref inner) => if let Some(initp) = init {
-            if let ExprKind::Box(ref inner_init) = initp.node {
-                check_pat(cx, inner, Some(&**inner_init), span, bindings);
+        PatKind::Box(ref inner) => {
+            if let Some(initp) = init {
+                if let ExprKind::Box(ref inner_init) = initp.node {
+                    check_pat(cx, inner, Some(&**inner_init), span, bindings);
+                } else {
+                    check_pat(cx, inner, init, span, bindings);
+                }
             } else {
                 check_pat(cx, inner, init, span, bindings);
             }
-        } else {
-            check_pat(cx, inner, init, span, bindings);
         },
         PatKind::Ref(ref inner, _) => check_pat(cx, inner, init, span, bindings),
         // PatVec(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
@@ -313,14 +314,9 @@ fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings:
         ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, _, _) => check_block(cx, block, bindings),
         // ExprKind::Call
         // ExprKind::MethodCall
-        ExprKind::Array(ref v) | ExprKind::Tup(ref v) => for e in v {
-            check_expr(cx, e, bindings)
-        },
-        ExprKind::If(ref cond, ref then, ref otherwise) => {
-            check_expr(cx, cond, bindings);
-            check_expr(cx, &**then, bindings);
-            if let Some(ref o) = *otherwise {
-                check_expr(cx, o, bindings);
+        ExprKind::Array(ref v) | ExprKind::Tup(ref v) => {
+            for e in v {
+                check_expr(cx, e, bindings)
             }
         },
         ExprKind::While(ref cond, ref block, _) => {
@@ -335,7 +331,9 @@ fn check_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr, bindings:
                     check_pat(cx, pat, Some(&**init), pat.span, bindings);
                     // This is ugly, but needed to get the right type
                     if let Some(ref guard) = arm.guard {
-                        check_expr(cx, guard, bindings);
+                        match guard {
+                            Guard::If(if_expr) => check_expr(cx, if_expr, bindings),
+                        }
                     }
                     check_expr(cx, &arm.body, bindings);
                     bindings.truncate(len);
@@ -351,13 +349,17 @@ fn check_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: &'tcx Ty, bindings: &mut V
         TyKind::Slice(ref sty) => check_ty(cx, sty, bindings),
         TyKind::Array(ref fty, ref anon_const) => {
             check_ty(cx, fty, bindings);
-            check_expr(cx, &cx.tcx.hir.body(anon_const.body).value, bindings);
+            check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings);
+        },
+        TyKind::Ptr(MutTy { ty: ref mty, .. }) | TyKind::Rptr(_, MutTy { ty: ref mty, .. }) => {
+            check_ty(cx, mty, bindings)
         },
-        TyKind::Ptr(MutTy { ty: ref mty, .. }) | TyKind::Rptr(_, MutTy { ty: ref mty, .. }) => check_ty(cx, mty, bindings),
-        TyKind::Tup(ref tup) => for t in tup {
-            check_ty(cx, t, bindings)
+        TyKind::Tup(ref tup) => {
+            for t in tup {
+                check_ty(cx, t, bindings)
+            }
         },
-        TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir.body(anon_const.body).value, bindings),
+        TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
         _ => (),
     }
 }
@@ -366,11 +368,7 @@ fn is_self_shadow(name: Name, expr: &Expr) -> bool {
     match expr.node {
         ExprKind::Box(ref inner) | ExprKind::AddrOf(_, ref inner) => is_self_shadow(name, inner),
         ExprKind::Block(ref block, _) => {
-            block.stmts.is_empty()
-                && block
-                    .expr
-                    .as_ref()
-                    .map_or(false, |e| is_self_shadow(name, e))
+            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |e| is_self_shadow(name, e))
         },
         ExprKind::Unary(op, ref inner) => (UnDeref == op) && is_self_shadow(name, inner),
         ExprKind::Path(QPath::Resolved(_, ref path)) => path_eq_name(name, path),
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
new file mode 100644 (file)
index 0000000..d84602c
--- /dev/null
@@ -0,0 +1,320 @@
+use crate::utils::sugg::Sugg;
+use crate::utils::sym;
+use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq};
+use if_chain::if_chain;
+use rustc::hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor};
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::ast::LitKind;
+use syntax_pos::symbol::Symbol;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks slow zero-filled vector initialization
+    ///
+    /// **Why is this bad?** These structures are non-idiomatic and less efficient than simply using
+    /// `vec![0; len]`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut vec1 = Vec::with_capacity(len);
+    /// vec1.resize(len, 0);
+    ///
+    /// let mut vec2 = Vec::with_capacity(len);
+    /// vec2.extend(repeat(0).take(len))
+    /// ```
+    pub SLOW_VECTOR_INITIALIZATION,
+    perf,
+    "slow vector initialization"
+}
+
+declare_lint_pass!(SlowVectorInit => [SLOW_VECTOR_INITIALIZATION]);
+
+/// `VecAllocation` contains data regarding a vector allocated with `with_capacity` and then
+/// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or
+/// `vec = Vec::with_capacity(0)`
+struct VecAllocation<'tcx> {
+    /// Symbol of the local variable name
+    variable_name: Symbol,
+
+    /// Reference to the expression which allocates the vector
+    allocation_expr: &'tcx Expr,
+
+    /// Reference to the expression used as argument on `with_capacity` call. This is used
+    /// to only match slow zero-filling idioms of the same length than vector initialization.
+    len_expr: &'tcx Expr,
+}
+
+/// Type of slow initialization
+enum InitializationType<'tcx> {
+    /// Extend is a slow initialization with the form `vec.extend(repeat(0).take(..))`
+    Extend(&'tcx Expr),
+
+    /// Resize is a slow initialization with the form `vec.resize(.., 0)`
+    Resize(&'tcx Expr),
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SlowVectorInit {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
+        if_chain! {
+            if let ExprKind::Assign(ref left, ref right) = expr.node;
+
+            // Extract variable name
+            if let ExprKind::Path(QPath::Resolved(_, ref path)) = left.node;
+            if let Some(variable_name) = path.segments.get(0);
+
+            // Extract len argument
+            if let Some(ref len_arg) = Self::is_vec_with_capacity(right);
+
+            then {
+                let vi = VecAllocation {
+                    variable_name: variable_name.ident.name,
+                    allocation_expr: right,
+                    len_expr: len_arg,
+                };
+
+                Self::search_initialization(cx, vi, expr.hir_id);
+            }
+        }
+    }
+
+    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
+        // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
+        if_chain! {
+            if let StmtKind::Local(ref local) = stmt.node;
+            if let PatKind::Binding(BindingAnnotation::Mutable, .., variable_name, None) = local.pat.node;
+            if let Some(ref init) = local.init;
+            if let Some(ref len_arg) = Self::is_vec_with_capacity(init);
+
+            then {
+                let vi = VecAllocation {
+                    variable_name: variable_name.name,
+                    allocation_expr: init,
+                    len_expr: len_arg,
+                };
+
+                Self::search_initialization(cx, vi, stmt.hir_id);
+            }
+        }
+    }
+}
+
+impl SlowVectorInit {
+    /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
+    /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
+    fn is_vec_with_capacity(expr: &Expr) -> Option<&Expr> {
+        if_chain! {
+            if let ExprKind::Call(ref func, ref args) = expr.node;
+            if let ExprKind::Path(ref path) = func.node;
+            if match_qpath(path, &[*sym::Vec, *sym::with_capacity]);
+            if args.len() == 1;
+
+            then {
+                return Some(&args[0]);
+            }
+        }
+
+        None
+    }
+
+    /// Search initialization for the given vector
+    fn search_initialization<'tcx>(cx: &LateContext<'_, 'tcx>, vec_alloc: VecAllocation<'tcx>, parent_node: HirId) {
+        let enclosing_body = get_enclosing_block(cx, parent_node);
+
+        if enclosing_body.is_none() {
+            return;
+        }
+
+        let mut v = VectorInitializationVisitor {
+            cx,
+            vec_alloc,
+            slow_expression: None,
+            initialization_found: false,
+        };
+
+        v.visit_block(enclosing_body.unwrap());
+
+        if let Some(ref allocation_expr) = v.slow_expression {
+            Self::lint_initialization(cx, allocation_expr, &v.vec_alloc);
+        }
+    }
+
+    fn lint_initialization<'tcx>(
+        cx: &LateContext<'_, 'tcx>,
+        initialization: &InitializationType<'tcx>,
+        vec_alloc: &VecAllocation<'_>,
+    ) {
+        match initialization {
+            InitializationType::Extend(e) | InitializationType::Resize(e) => Self::emit_lint(
+                cx,
+                e,
+                vec_alloc,
+                "slow zero-filling initialization",
+                SLOW_VECTOR_INITIALIZATION,
+            ),
+        };
+    }
+
+    fn emit_lint<'tcx>(
+        cx: &LateContext<'_, 'tcx>,
+        slow_fill: &Expr,
+        vec_alloc: &VecAllocation<'_>,
+        msg: &str,
+        lint: &'static Lint,
+    ) {
+        let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");
+
+        span_lint_and_then(cx, lint, slow_fill.span, msg, |db| {
+            db.span_suggestion(
+                vec_alloc.allocation_expr.span,
+                "consider replace allocation with",
+                format!("vec![0; {}]", len_expr),
+                Applicability::Unspecified,
+            );
+        });
+    }
+}
+
+/// `VectorInitializationVisitor` searches for unsafe or slow vector initializations for the given
+/// vector.
+struct VectorInitializationVisitor<'a, 'tcx: 'a> {
+    cx: &'a LateContext<'a, 'tcx>,
+
+    /// Contains the information.
+    vec_alloc: VecAllocation<'tcx>,
+
+    /// Contains the slow initialization expression, if one was found.
+    slow_expression: Option<InitializationType<'tcx>>,
+
+    /// `true` if the initialization of the vector has been found on the visited block.
+    initialization_found: bool,
+}
+
+impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
+    /// Checks if the given expression is extending a vector with `repeat(0).take(..)`
+    fn search_slow_extend_filling(&mut self, expr: &'tcx Expr) {
+        if_chain! {
+            if self.initialization_found;
+            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
+            if let ExprKind::Path(ref qpath_subj) = args[0].node;
+            if match_qpath(&qpath_subj, &[self.vec_alloc.variable_name]);
+            if path.ident.name == *sym::extend;
+            if let Some(ref extend_arg) = args.get(1);
+            if self.is_repeat_take(extend_arg);
+
+            then {
+                self.slow_expression = Some(InitializationType::Extend(expr));
+            }
+        }
+    }
+
+    /// Checks if the given expression is resizing a vector with 0
+    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr) {
+        if_chain! {
+            if self.initialization_found;
+            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
+            if let ExprKind::Path(ref qpath_subj) = args[0].node;
+            if match_qpath(&qpath_subj, &[self.vec_alloc.variable_name]);
+            if path.ident.name == *sym::resize;
+            if let (Some(ref len_arg), Some(fill_arg)) = (args.get(1), args.get(2));
+
+            // Check that is filled with 0
+            if let ExprKind::Lit(ref lit) = fill_arg.node;
+            if let LitKind::Int(0, _) = lit.node;
+
+            // Check that len expression is equals to `with_capacity` expression
+            if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);
+
+            then {
+                self.slow_expression = Some(InitializationType::Resize(expr));
+            }
+        }
+    }
+
+    /// Returns `true` if give expression is `repeat(0).take(...)`
+    fn is_repeat_take(&self, expr: &Expr) -> bool {
+        if_chain! {
+            if let ExprKind::MethodCall(ref take_path, _, ref take_args) = expr.node;
+            if take_path.ident.name == *sym::take;
+
+            // Check that take is applied to `repeat(0)`
+            if let Some(ref repeat_expr) = take_args.get(0);
+            if self.is_repeat_zero(repeat_expr);
+
+            // Check that len expression is equals to `with_capacity` expression
+            if let Some(ref len_arg) = take_args.get(1);
+            if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr);
+
+            then {
+                return true;
+            }
+        }
+
+        false
+    }
+
+    /// Returns `true` if given expression is `repeat(0)`
+    fn is_repeat_zero(&self, expr: &Expr) -> bool {
+        if_chain! {
+            if let ExprKind::Call(ref fn_expr, ref repeat_args) = expr.node;
+            if let ExprKind::Path(ref qpath_repeat) = fn_expr.node;
+            if match_qpath(&qpath_repeat, &[*sym::repeat]);
+            if let Some(ref repeat_arg) = repeat_args.get(0);
+            if let ExprKind::Lit(ref lit) = repeat_arg.node;
+            if let LitKind::Int(0, _) = lit.node;
+
+            then {
+                return true
+            }
+        }
+
+        false
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
+    fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
+        if self.initialization_found {
+            match stmt.node {
+                StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
+                    self.search_slow_extend_filling(expr);
+                    self.search_slow_resize_filling(expr);
+                },
+                _ => (),
+            }
+
+            self.initialization_found = false;
+        } else {
+            walk_stmt(self, stmt);
+        }
+    }
+
+    fn visit_block(&mut self, block: &'tcx Block) {
+        if self.initialization_found {
+            if let Some(ref s) = block.stmts.get(0) {
+                self.visit_stmt(s)
+            }
+
+            self.initialization_found = false;
+        } else {
+            walk_block(self, block);
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr) {
+        // Skip all the expressions previous to the vector initialization
+        if self.vec_alloc.allocation_expr.hir_id == expr.hir_id {
+            self.initialization_found = true;
+        }
+
+        walk_expr(self, expr);
+    }
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+}
index a13f864c5ce7debea72e0c385d1f92c84de45c9e..b6b0ca822c81106f53e19984ac59aa5c929b633c 100644 (file)
@@ -1,91 +1,93 @@
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use syntax::codemap::Spanned;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::source_map::Spanned;
+
+use crate::utils::sym;
 use crate::utils::SpanlessEq;
 use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty};
 
-/// **What it does:** Checks for string appends of the form `x = x + y` (without
-/// `let`!).
-///
-/// **Why is this bad?** It's not really bad, but some people think that the
-/// `.push_str(_)` method is more readable. Also creates a new heap allocation and throws
-/// away the old one.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// let mut x = "Hello".to_owned();
-/// x = x + ", World";
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for string appends of the form `x = x + y` (without
+    /// `let`!).
+    ///
+    /// **Why is this bad?** It's not really bad, but some people think that the
+    /// `.push_str(_)` method is more readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let mut x = "Hello".to_owned();
+    /// x = x + ", World";
+    /// ```
     pub STRING_ADD_ASSIGN,
     pedantic,
     "using `x = x + ..` where x is a `String` instead of `push_str()`"
 }
 
-/// **What it does:** Checks for all instances of `x + _` where `x` is of type
-/// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
-/// match.
-///
-/// **Why is this bad?** It's not bad in and of itself. However, this particular
-/// `Add` implementation is asymmetric (the other operand need not be `String`,
-/// but `x` does), while addition as mathematically defined is symmetric, also
-/// the `String::push_str(_)` function is a perfectly good replacement.
-/// Therefore some dislike it and wish not to have it in their code.
-///
-/// That said, other people think that string addition, having a long tradition
-/// in other languages is actually fine, which is why we decided to make this
-/// particular lint `allow` by default.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// let x = "Hello".to_owned();
-/// x + ", World"
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for all instances of `x + _` where `x` is of type
+    /// `String`, but only if [`string_add_assign`](#string_add_assign) does *not*
+    /// match.
+    ///
+    /// **Why is this bad?** It's not bad in and of itself. However, this particular
+    /// `Add` implementation is asymmetric (the other operand need not be `String`,
+    /// but `x` does), while addition as mathematically defined is symmetric, also
+    /// the `String::push_str(_)` function is a perfectly good replacement.
+    /// Therefore, some dislike it and wish not to have it in their code.
+    ///
+    /// That said, other people think that string addition, having a long tradition
+    /// in other languages is actually fine, which is why we decided to make this
+    /// particular lint `allow` by default.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x = "Hello".to_owned();
+    /// x + ", World"
+    /// ```
     pub STRING_ADD,
     restriction,
     "using `x + ..` where x is a `String` instead of `push_str()`"
 }
 
-/// **What it does:** Checks for the `as_bytes` method called on string literals
-/// that contain only ASCII characters.
-///
-/// **Why is this bad?** Byte string literals (e.g. `b"foo"`) can be used
-/// instead. They are shorter but less discoverable than `as_bytes()`.
-///
-/// **Known Problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let bs = "a byte string".as_bytes();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for the `as_bytes` method called on string literals
+    /// that contain only ASCII characters.
+    ///
+    /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
+    /// instead. They are shorter but less discoverable than `as_bytes()`.
+    ///
+    /// **Known Problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let bs = "a byte string".as_bytes();
+    /// ```
     pub STRING_LIT_AS_BYTES,
     style,
     "calling `as_bytes` on a string literal instead of using a byte string literal"
 }
 
-#[derive(Copy, Clone)]
-pub struct StringAdd;
-
-impl LintPass for StringAdd {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(STRING_ADD, STRING_ADD_ASSIGN)
-    }
-}
+declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringAdd {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if let ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) = e.node {
+        if let ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Add, ..
+            },
+            ref left,
+            _,
+        ) = e.node
+        {
             if is_string(cx, left) {
-                if !is_allowed(cx, STRING_ADD_ASSIGN, e.id) {
+                if !is_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
                     let parent = get_parent_expr(cx, e);
                     if let Some(p) = parent {
                         if let ExprKind::Assign(ref target, _) = p.node {
@@ -118,49 +120,73 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
 }
 
 fn is_string(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
-    match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), &paths::STRING)
+    match_type(cx, walk_ptrs_ty(cx.tables.expr_ty(e)), &*paths::STRING)
 }
 
 fn is_add(cx: &LateContext<'_, '_>, src: &Expr, target: &Expr) -> bool {
     match src.node {
-        ExprKind::Binary(Spanned { node: BinOpKind::Add, .. }, ref left, _) => SpanlessEq::new(cx).eq_expr(target, left),
+        ExprKind::Binary(
+            Spanned {
+                node: BinOpKind::Add, ..
+            },
+            ref left,
+            _,
+        ) => SpanlessEq::new(cx).eq_expr(target, left),
         ExprKind::Block(ref block, _) => {
-            block.stmts.is_empty()
-                && block
-                    .expr
-                    .as_ref()
-                    .map_or(false, |expr| is_add(cx, expr, target))
+            block.stmts.is_empty() && block.expr.as_ref().map_or(false, |expr| is_add(cx, expr, target))
         },
         _ => false,
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct StringLitAsBytes;
-
-impl LintPass for StringLitAsBytes {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(STRING_LIT_AS_BYTES)
-    }
-}
+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 syntax::ast::LitKind;
-        use crate::utils::{in_macro, snippet};
+        use crate::utils::{in_macro_or_desugar, snippet, snippet_with_applicability};
+        use syntax::ast::{LitKind, StrStyle};
 
         if let ExprKind::MethodCall(ref path, _, ref args) = e.node {
-            if path.ident.name == "as_bytes" {
+            if path.ident.name == *sym::as_bytes {
                 if let ExprKind::Lit(ref lit) = args[0].node {
-                    if let LitKind::Str(ref lit_content, _) = lit.node {
-                        if lit_content.as_str().chars().all(|c| c.is_ascii()) && !in_macro(args[0].span) {
+                    if let LitKind::Str(ref lit_content, style) = lit.node {
+                        let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
+                        let expanded = if let StrStyle::Raw(n) = style {
+                            let term = (0..n).map(|_| '#').collect::<String>();
+                            format!("r{0}\"{1}\"{0}", term, lit_content.as_str())
+                        } else {
+                            format!("\"{}\"", lit_content.as_str())
+                        };
+                        let mut applicability = Applicability::MachineApplicable;
+                        if callsite.starts_with("include_str!") {
+                            span_lint_and_sugg(
+                                cx,
+                                STRING_LIT_AS_BYTES,
+                                e.span,
+                                "calling `as_bytes()` on `include_str!(..)`",
+                                "consider using `include_bytes!(..)` instead",
+                                snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
+                                    "include_str",
+                                    "include_bytes",
+                                    1,
+                                ),
+                                applicability,
+                            );
+                        } else if callsite == expanded
+                            && lit_content.as_str().chars().all(|c| c.is_ascii())
+                            && !in_macro_or_desugar(args[0].span)
+                        {
                             span_lint_and_sugg(
                                 cx,
                                 STRING_LIT_AS_BYTES,
                                 e.span,
                                 "calling `as_bytes()` on a string literal",
                                 "consider using a byte string literal instead",
-                                format!("b{}", snippet(cx, args[0].span, r#""foo""#)),
+                                format!(
+                                    "b{}",
+                                    snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
+                                ),
+                                applicability,
                             );
                         }
                     }
index b0a8a2d00617cff2a85fab7cf07f85dbbe5c6de6..ecc033937ab58d2b9f3c43d32130f4335d196f35 100644 (file)
@@ -1,82 +1,75 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::sym;
+use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method};
 use if_chain::if_chain;
 use rustc::hir;
 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use syntax::ast;
-use crate::utils::{get_trait_def_id, span_lint};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::symbol::Symbol;
 
-/// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g.
-/// subtracting elements in an Add impl.
-///
-/// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// impl Add for Foo {
-///     type Output = Foo;
-///
-///     fn add(self, other: Foo) -> Foo {
-///         Foo(self.0 - other.0)
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Lints for suspicious operations in impls of arithmetic operators, e.g.
+    /// subtracting elements in an Add impl.
+    ///
+    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// impl Add for Foo {
+    ///     type Output = Foo;
+    ///
+    ///     fn add(self, other: Foo) -> Foo {
+    ///         Foo(self.0 - other.0)
+    ///     }
+    /// }
+    /// ```
     pub SUSPICIOUS_ARITHMETIC_IMPL,
     correctness,
     "suspicious use of operators in impl of arithmetic trait"
 }
 
-/// **What it does:** Lints for suspicious operations in impls of OpAssign, e.g.
-/// subtracting elements in an AddAssign impl.
-///
-/// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// impl AddAssign for Foo {
-///     fn add_assign(&mut self, other: Foo) {
-///         *self = *self - other;
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Lints for suspicious operations in impls of OpAssign, e.g.
+    /// subtracting elements in an AddAssign impl.
+    ///
+    /// **Why this is bad?** This is probably a typo or copy-and-paste error and not intended.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// impl AddAssign for Foo {
+    ///     fn add_assign(&mut self, other: Foo) {
+    ///         *self = *self - other;
+    ///     }
+    /// }
+    /// ```
     pub SUSPICIOUS_OP_ASSIGN_IMPL,
     correctness,
     "suspicious use of operators in impl of OpAssign trait"
 }
 
-#[derive(Copy, Clone)]
-pub struct SuspiciousImpl;
-
-impl LintPass for SuspiciousImpl {
-    fn get_lints(&self) -> LintArray {
-        lint_array![SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL]
-    }
-}
+declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_ASSIGN_IMPL]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
         if let hir::ExprKind::Binary(binop, _, _) = expr.node {
             match binop.node {
-                hir::BinOpKind::Eq
+                hir::BinOpKind::Eq
                 | hir::BinOpKind::Lt
                 | hir::BinOpKind::Le
                 | hir::BinOpKind::Ne
                 | hir::BinOpKind::Ge
-                | hir::BinOpKind::Gt
-                => return,
+                | hir::BinOpKind::Gt => return,
                 _ => {},
             }
             // Check if the binary expression is part of another bi/unary expression
             // as a child node
-            let mut parent_expr = cx.tcx.hir.get_parent_node(expr.id);
-            while parent_expr != ast::CRATE_NODE_ID {
-                if let hir::map::Node::NodeExpr(e) = cx.tcx.hir.get(parent_expr) {
+            let mut parent_expr = cx.tcx.hir().get_parent_node_by_hir_id(expr.hir_id);
+            while parent_expr != hir::CRATE_HIR_ID {
+                if let hir::Node::Expr(e) = cx.tcx.hir().get_by_hir_id(parent_expr) {
                     match e.node {
                         hir::ExprKind::Binary(..)
                         | hir::ExprKind::Unary(hir::UnOp::UnNot, _)
@@ -84,12 +77,10 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                         _ => {},
                     }
                 }
-                parent_expr = cx.tcx.hir.get_parent_node(parent_expr);
+                parent_expr = cx.tcx.hir().get_parent_node_by_hir_id(parent_expr);
             }
             // as a parent node
-            let mut visitor = BinaryExprVisitor {
-                in_binary_expr: false,
-            };
+            let mut visitor = BinaryExprVisitor { in_binary_expr: false };
             walk_expr(&mut visitor, expr);
 
             if visitor.in_binary_expr {
@@ -100,7 +91,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                 cx,
                 expr,
                 binop.node,
-                &["Add", "Sub", "Mul", "Div"],
+                &[*sym::Add, *sym::Sub, *sym::Mul, *sym::Div],
                 &[
                     hir::BinOpKind::Add,
                     hir::BinOpKind::Sub,
@@ -112,10 +103,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                     cx,
                     SUSPICIOUS_ARITHMETIC_IMPL,
                     binop.span,
-                    &format!(
-                        r#"Suspicious use of binary operator in `{}` impl"#,
-                        impl_trait
-                    ),
+                    &format!(r#"Suspicious use of binary operator in `{}` impl"#, impl_trait),
                 );
             }
 
@@ -124,16 +112,16 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                 expr,
                 binop.node,
                 &[
-                    "AddAssign",
-                    "SubAssign",
-                    "MulAssign",
-                    "DivAssign",
-                    "BitAndAssign",
-                    "BitOrAssign",
-                    "BitXorAssign",
-                    "RemAssign",
-                    "ShlAssign",
-                    "ShrAssign",
+                    *sym::AddAssign,
+                    *sym::SubAssign,
+                    *sym::MulAssign,
+                    *sym::DivAssign,
+                    *sym::BitAndAssign,
+                    *sym::BitOrAssign,
+                    *sym::BitXorAssign,
+                    *sym::RemAssign,
+                    *sym::ShlAssign,
+                    *sym::ShrAssign,
                 ],
                 &[
                     hir::BinOpKind::Add,
@@ -152,27 +140,24 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                     cx,
                     SUSPICIOUS_OP_ASSIGN_IMPL,
                     binop.span,
-                    &format!(
-                        r#"Suspicious use of binary operator in `{}` impl"#,
-                        impl_trait
-                    ),
+                    &format!(r#"Suspicious use of binary operator in `{}` impl"#, impl_trait),
                 );
             }
         }
     }
 }
 
-fn check_binop<'a>(
+fn check_binop(
     cx: &LateContext<'_, '_>,
     expr: &hir::Expr,
     binop: hir::BinOpKind,
-    traits: &[&'a str],
+    traits: &[Symbol],
     expected_ops: &[hir::BinOpKind],
-) -> Option<&'a str> {
+) -> Option<Symbol> {
     let mut trait_ids = vec![];
-    let [krate, module] = crate::utils::paths::OPS_MODULE;
+    let [krate, module] = *crate::utils::paths::OPS_MODULE;
 
-    for t in traits {
+    for &t in traits {
         let path = [krate, module, t];
         if let Some(trait_id) = get_trait_def_id(cx, &path) {
             trait_ids.push(trait_id);
@@ -182,14 +167,11 @@ fn check_binop<'a>(
     }
 
     // Get the actually implemented trait
-    let parent_fn = cx.tcx.hir.get_parent(expr.id);
-    let parent_impl = cx.tcx.hir.get_parent(parent_fn);
+    let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
 
     if_chain! {
-        if parent_impl != ast::CRATE_NODE_ID;
-        if let hir::map::Node::NodeItem(item) = cx.tcx.hir.get(parent_impl);
-        if let hir::ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.node;
-        if let Some(idx) = trait_ids.iter().position(|&tid| tid == trait_ref.path.def.def_id());
+        if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn);
+        if let Some(idx) = trait_ids.iter().position(|&tid| tid == trait_ref.path.res.def_id());
         if binop != expected_ops[idx];
         then{
             return Some(traits[idx])
@@ -208,9 +190,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprKind::Binary(..)
             | hir::ExprKind::Unary(hir::UnOp::UnNot, _)
-            | hir::ExprKind::Unary(hir::UnOp::UnNeg, _) => {
-                self.in_binary_expr = true
-            },
+            | hir::ExprKind::Unary(hir::UnOp::UnNeg, _) => self.in_binary_expr = true,
             _ => {},
         }
 
index 38369d05676ca4501dda009231ef92dccacbf784..cb3a9465a77eaac85e02b07a15e599da1d831e25 100644 (file)
@@ -1,56 +1,58 @@
+use crate::utils::sugg::Sugg;
+use crate::utils::{
+    differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq,
+};
+use if_chain::if_chain;
 use matches::matches;
 use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use crate::utils::{differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq};
-use crate::utils::sugg::Sugg;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 
-/// **What it does:** Checks for manual swapping.
-///
-/// **Why is this bad?** The `std::mem::swap` function exposes the intent better
-/// without deinitializing or copying either variable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// let t = b;
-/// b = a;
-/// a = t;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for manual swapping.
+    ///
+    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
+    /// without deinitializing or copying either variable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let t = b;
+    /// b = a;
+    /// a = t;
+    /// ```
+    /// Use std::mem::swap():
+    /// ```rust
+    /// std::mem::swap(&mut a, &mut b);
+    /// ```
     pub MANUAL_SWAP,
     complexity,
     "manual swap of two variables"
 }
 
-/// **What it does:** Checks for `foo = bar; bar = foo` sequences.
-///
-/// **Why is this bad?** This looks like a failed attempt to swap.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// a = b;
-/// b = a;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
+    ///
+    /// **Why is this bad?** This looks like a failed attempt to swap.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let mut a = 1;
+    /// # let mut b = 2;
+    /// a = b;
+    /// b = a;
+    /// ```
     pub ALMOST_SWAPPED,
     correctness,
     "`foo = bar; bar = foo` sequence"
 }
 
-#[derive(Copy, Clone)]
-pub struct Swap;
-
-impl LintPass for Swap {
-    fn get_lints(&self) -> LintArray {
-        lint_array![MANUAL_SWAP, ALMOST_SWAPPED]
-    }
-}
+declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
     fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
@@ -64,17 +66,16 @@ fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) {
     for w in block.stmts.windows(3) {
         if_chain! {
             // let t = foo();
-            if let StmtKind::Decl(ref tmp, _) = w[0].node;
-            if let DeclKind::Local(ref tmp) = tmp.node;
+            if let StmtKind::Local(ref tmp) = w[0].node;
             if let Some(ref tmp_init) = tmp.init;
-            if let PatKind::Binding(_, _, ident, None) = tmp.pat.node;
+            if let PatKind::Binding(.., ident, None) = tmp.pat.node;
 
             // foo() = bar();
-            if let StmtKind::Semi(ref first, _) = w[1].node;
+            if let StmtKind::Semi(ref first) = w[1].node;
             if let ExprKind::Assign(ref lhs1, ref rhs1) = first.node;
 
             // bar() = t;
-            if let StmtKind::Semi(ref second, _) = w[2].node;
+            if let StmtKind::Semi(ref second) = w[2].node;
             if let ExprKind::Assign(ref lhs2, ref rhs2) = second.node;
             if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.node;
             if rhs2.segments.len() == 1;
@@ -93,10 +94,10 @@ fn check_for_slice<'a>(
                             if SpanlessEq::new(cx).ignore_fn().eq_expr(lhs1, lhs2) {
                                 let ty = walk_ptrs_ty(cx.tables.expr_ty(lhs1));
 
-                                if matches!(ty.sty, ty::TySlice(_)) ||
-                                    matches!(ty.sty, ty::TyArray(_, _)) ||
-                                    match_type(cx, ty, &paths::VEC) ||
-                                    match_type(cx, ty, &paths::VEC_DEQUE) {
+                                if matches!(ty.sty, ty::Slice(_)) ||
+                                    matches!(ty.sty, ty::Array(_, _)) ||
+                                    match_type(cx, ty, &*paths::VEC) ||
+                                    match_type(cx, ty, &*paths::VEC_DEQUE) {
                                         return Some((lhs1, idx1, idx2));
                                 }
                             }
@@ -115,13 +116,13 @@ fn check_for_slice<'a>(
                                  snippet(cx, idx1.span, ".."),
                                  snippet(cx, idx2.span, "..")))
                     } else {
-                        (false, "".to_owned(), "".to_owned())
+                        (false, String::new(), String::new())
                     }
                 } else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
                     (true, format!(" `{}` and `{}`", first, second),
                         format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()))
                 } else {
-                    (true, "".to_owned(), "".to_owned())
+                    (true, String::new(), String::new())
                 };
 
                 let span = w[0].span.to(second.span);
@@ -132,7 +133,12 @@ fn check_for_slice<'a>(
                                    &format!("this looks like you are swapping{} manually", what),
                                    |db| {
                                        if !sugg.is_empty() {
-                                           db.span_suggestion(span, "try", sugg);
+                                           db.span_suggestion(
+                                               span,
+                                               "try",
+                                               sugg,
+                                               Applicability::Unspecified,
+                                           );
 
                                            if replace {
                                                db.note("or maybe you should use `std::mem::replace`?");
@@ -148,8 +154,8 @@ fn check_for_slice<'a>(
 fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
     for w in block.stmts.windows(2) {
         if_chain! {
-            if let StmtKind::Semi(ref first, _) = w[0].node;
-            if let StmtKind::Semi(ref second, _) = w[1].node;
+            if let StmtKind::Semi(ref first) = w[0].node;
+            if let StmtKind::Semi(ref second) = w[1].node;
             if !differing_macro_contexts(first.span, second.span);
             if let ExprKind::Assign(ref lhs0, ref rhs0) = first.node;
             if let ExprKind::Assign(ref lhs1, ref rhs1) = second.node;
@@ -165,7 +171,7 @@ fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
                         second.mut_addr().to_string(),
                     )
                 } else {
-                    ("".to_owned(), "".to_owned(), "".to_owned())
+                    (String::new(), String::new(), String::new())
                 };
 
                 let span = first.span.to(second.span);
@@ -176,8 +182,16 @@ fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
                                    &format!("this looks like you are trying to swap{}", what),
                                    |db| {
                                        if !what.is_empty() {
-                                           db.span_suggestion(span, "try",
-                                                              format!("std::mem::swap({}, {})", lhs, rhs));
+                                           db.span_suggestion(
+                                               span,
+                                               "try",
+                                               format!(
+                                                   "std::mem::swap({}, {})",
+                                                   lhs,
+                                                   rhs,
+                                               ),
+                                               Applicability::MaybeIncorrect,
+                                           );
                                            db.note("or maybe you should use `std::mem::replace`?");
                                        }
                                    });
index 56e705ad0a7217143029d42ff29015f1d4a80ceb..81054c0d1f1d3b06734ee3b53d704b086f9d0ac7 100644 (file)
@@ -1,50 +1,53 @@
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use rustc::{declare_lint, lint_array};
-use rustc::hir::{Expr, ExprKind};
 use crate::utils::is_adjusted;
 use crate::utils::span_lint;
+use rustc::hir::def::{DefKind, Res};
+use rustc::hir::{Expr, ExprKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for construction of a structure or tuple just to
-/// assign a value in it.
-///
-/// **Why is this bad?** Readability. If the structure is only created to be
-/// updated, why not write the structure you want in the first place?
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// (0, 0).0 = 1
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for construction of a structure or tuple just to
+    /// assign a value in it.
+    ///
+    /// **Why is this bad?** Readability. If the structure is only created to be
+    /// updated, why not write the structure you want in the first place?
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// (0, 0).0 = 1
+    /// ```
     pub TEMPORARY_ASSIGNMENT,
     complexity,
     "assignments to temporaries"
 }
 
-fn is_temporary(expr: &Expr) -> bool {
-    match expr.node {
+fn is_temporary(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
+    match &expr.node {
         ExprKind::Struct(..) | ExprKind::Tup(..) => true,
+        ExprKind::Path(qpath) => {
+            if let Res::Def(DefKind::Const, ..) = cx.tables.qpath_res(qpath, expr.hir_id) {
+                true
+            } else {
+                false
+            }
+        },
         _ => false,
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct Pass;
+declare_lint_pass!(TemporaryAssignment => [TEMPORARY_ASSIGNMENT]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(TEMPORARY_ASSIGNMENT)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TemporaryAssignment {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if let ExprKind::Assign(ref target, _) = expr.node {
-            if let ExprKind::Field(ref base, _) = target.node {
-                if is_temporary(base) && !is_adjusted(cx, base) {
-                    span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary");
-                }
+        if let ExprKind::Assign(target, _) = &expr.node {
+            let mut base = target;
+            while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.node {
+                base = f;
+            }
+            if is_temporary(cx, base) && !is_adjusted(cx, base) {
+                span_lint(cx, TEMPORARY_ASSIGNMENT, expr.span, "assignment to temporary");
             }
         }
     }
index 403aeb47402077d143d7f28a1a3009a1d44f8f77..45d80e3f5e3a231191277903e1b0e32fa47f040c 100644 (file)
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then, sugg};
 use if_chain::if_chain;
-use rustc::ty::{self, Ty};
 use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use std::borrow::Cow;
 use syntax::ast;
-use crate::utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then};
-use crate::utils::{opt_def_id, sugg};
 
-/// **What it does:** Checks for transmutes that can't ever be correct on any
-/// architecture.
-///
-/// **Why is this bad?** It's basically guaranteed to be undefined behaviour.
-///
-/// **Known problems:** When accessing C, users might want to store pointer
-/// sized objects in `extradata` arguments to save an allocation.
-///
-/// **Example:**
-/// ```rust
-/// let ptr: *const T = core::intrinsics::transmute('x')
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes that can't ever be correct on any
+    /// architecture.
+    ///
+    /// **Why is this bad?** It's basically guaranteed to be undefined behaviour.
+    ///
+    /// **Known problems:** When accessing C, users might want to store pointer
+    /// sized objects in `extradata` arguments to save an allocation.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// let ptr: *const T = core::intrinsics::transmute('x')
+    /// ```
     pub WRONG_TRANSMUTE,
     correctness,
     "transmutes that are confusing at best, undefined behaviour at worst and always useless"
 }
 
-/// **What it does:** Checks for transmutes to the original type of the object
-/// and transmutes that could be a cast.
-///
-/// **Why is this bad?** Readability. The code tricks people into thinking that
-/// something complex is going on.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// core::intrinsics::transmute(t) // where the result type is the same as `t`'s
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes to the original type of the object
+    /// and transmutes that could be a cast.
+    ///
+    /// **Why is this bad?** Readability. The code tricks people into thinking that
+    /// something complex is going on.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// core::intrinsics::transmute(t) // where the result type is the same as `t`'s
+    /// ```
     pub USELESS_TRANSMUTE,
     complexity,
     "transmutes that have the same to and from types or could be a cast/coercion"
 }
 
-/// **What it does:** Checks for transmutes between a type `T` and `*T`.
-///
-/// **Why is this bad?** It's easy to mistakenly transmute between a type and a
-/// pointer to that type.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// core::intrinsics::transmute(t) // where the result type is the same as
-/// // `*t` or `&t`'s
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes between a type `T` and `*T`.
+    ///
+    /// **Why is this bad?** It's easy to mistakenly transmute between a type and a
+    /// pointer to that type.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// core::intrinsics::transmute(t) // where the result type is the same as
+    ///                                // `*t` or `&t`'s
+    /// ```
     pub CROSSPOINTER_TRANSMUTE,
     complexity,
     "transmutes that have to or from types that are a pointer to the other"
 }
 
-/// **What it does:** Checks for transmutes from a pointer to a reference.
-///
-/// **Why is this bad?** This can always be rewritten with `&` and `*`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let _: &T = std::mem::transmute(p); // where p: *const T
-/// // can be written:
-/// let _: &T = &*p;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes from a pointer to a reference.
+    ///
+    /// **Why is this bad?** This can always be rewritten with `&` and `*`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _: &T = std::mem::transmute(p); // where p: *const T
+    ///
+    /// // can be written:
+    /// let _: &T = &*p;
+    /// ```
     pub TRANSMUTE_PTR_TO_REF,
     complexity,
     "transmutes from a pointer to a reference type"
 }
 
-/// **What it does:** Checks for transmutes from an integer to a `char`.
-///
-/// **Why is this bad?** Not every integer is a Unicode scalar value.
-///
-/// **Known problems:**
-/// - [`from_u32`] which this lint suggests using is slower than `transmute`
-/// as it needs to validate the input.
-/// If you are certain that the input is always a valid Unicode scalar value,
-/// use [`from_u32_unchecked`] which is as fast as `transmute`
-/// but has a semantically meaningful name.
-/// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
-///
-/// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
-/// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
-///
-/// **Example:**
-/// ```rust
-/// let _: char = std::mem::transmute(x); // where x: u32
-/// // should be:
-/// let _ = std::char::from_u32(x).unwrap();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes from an integer to a `char`.
+    ///
+    /// **Why is this bad?** Not every integer is a Unicode scalar value.
+    ///
+    /// **Known problems:**
+    /// - [`from_u32`] which this lint suggests using is slower than `transmute`
+    /// as it needs to validate the input.
+    /// If you are certain that the input is always a valid Unicode scalar value,
+    /// use [`from_u32_unchecked`] which is as fast as `transmute`
+    /// but has a semantically meaningful name.
+    /// - You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
+    ///
+    /// [`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
+    /// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _: char = std::mem::transmute(x); // where x: u32
+    ///
+    /// // should be:
+    /// let _ = std::char::from_u32(x).unwrap();
+    /// ```
     pub TRANSMUTE_INT_TO_CHAR,
     complexity,
     "transmutes from an integer to a `char`"
 }
 
-/// **What it does:** Checks for transmutes from a `&[u8]` to a `&str`.
-///
-/// **Why is this bad?** Not every byte slice is a valid UTF-8 string.
-///
-/// **Known problems:**
-/// - [`from_utf8`] which this lint suggests using is slower than `transmute`
-/// as it needs to validate the input.
-/// If you are certain that the input is always a valid UTF-8,
-/// use [`from_utf8_unchecked`] which is as fast as `transmute`
-/// but has a semantically meaningful name.
-/// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
-///
-/// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
-/// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
-///
-/// **Example:**
-/// ```rust
-/// let _: &str = std::mem::transmute(b); // where b: &[u8]
-/// // should be:
-/// let _ = std::str::from_utf8(b).unwrap();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes from a `&[u8]` to a `&str`.
+    ///
+    /// **Why is this bad?** Not every byte slice is a valid UTF-8 string.
+    ///
+    /// **Known problems:**
+    /// - [`from_utf8`] which this lint suggests using is slower than `transmute`
+    /// as it needs to validate the input.
+    /// If you are certain that the input is always a valid UTF-8,
+    /// use [`from_utf8_unchecked`] which is as fast as `transmute`
+    /// but has a semantically meaningful name.
+    /// - You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
+    ///
+    /// [`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
+    /// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _: &str = std::mem::transmute(b); // where b: &[u8]
+    ///
+    /// // should be:
+    /// let _ = std::str::from_utf8(b).unwrap();
+    /// ```
     pub TRANSMUTE_BYTES_TO_STR,
     complexity,
     "transmutes from a `&[u8]` to a `&str`"
 }
 
-/// **What it does:** Checks for transmutes from an integer to a `bool`.
-///
-/// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let _: bool = std::mem::transmute(x); // where x: u8
-/// // should be:
-/// let _: bool = x != 0;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes from an integer to a `bool`.
+    ///
+    /// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _: bool = std::mem::transmute(x); // where x: u8
+    ///
+    /// // should be:
+    /// let _: bool = x != 0;
+    /// ```
     pub TRANSMUTE_INT_TO_BOOL,
     complexity,
     "transmutes from an integer to a `bool`"
 }
 
-/// **What it does:** Checks for transmutes from an integer to a float.
-///
-/// **Why is this bad?** This might result in an invalid in-memory representation of a float.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let _: f32 = std::mem::transmute(x); // where x: u32
-/// // should be:
-/// let _: f32 = f32::from_bits(x);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes from an integer to a float.
+    ///
+    /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
+    /// and safe.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _: f32 = std::mem::transmute(x); // where x: u32
+    ///
+    /// // should be:
+    /// let _: f32 = f32::from_bits(x);
+    /// ```
     pub TRANSMUTE_INT_TO_FLOAT,
     complexity,
     "transmutes from an integer to a float"
 }
 
-/// **What it does:** Checks for transmutes from a pointer to a pointer, or
-/// from a reference to a reference.
-///
-/// **Why is this bad?** Transmutes are dangerous, and these can instead be
-/// written as casts.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let ptr = &1u32 as *const u32;
-/// unsafe {
-///     // pointer-to-pointer transmute
-///     let _: *const f32 = std::mem::transmute(ptr);
-///     // ref-ref transmute
-///     let _: &f32 = std::mem::transmute(&1u32);
-/// }
-/// // These can be respectively written:
-/// let _ = ptr as *const f32
-/// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for transmutes from a pointer to a pointer, or
+    /// from a reference to a reference.
+    ///
+    /// **Why is this bad?** Transmutes are dangerous, and these can instead be
+    /// written as casts.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let ptr = &1u32 as *const u32;
+    /// unsafe {
+    ///     // pointer-to-pointer transmute
+    ///     let _: *const f32 = std::mem::transmute(ptr);
+    ///     // ref-ref transmute
+    ///     let _: &f32 = std::mem::transmute(&1u32);
+    /// }
+    /// // These can be respectively written:
+    /// let _ = ptr as *const f32
+    /// let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
+    /// ```
     pub TRANSMUTE_PTR_TO_PTR,
     complexity,
     "transmutes from a pointer to a pointer / a reference to a reference"
 }
 
-pub struct Transmute;
-
-impl LintPass for Transmute {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            CROSSPOINTER_TRANSMUTE,
-            TRANSMUTE_PTR_TO_REF,
-            TRANSMUTE_PTR_TO_PTR,
-            USELESS_TRANSMUTE,
-            WRONG_TRANSMUTE,
-            TRANSMUTE_INT_TO_CHAR,
-            TRANSMUTE_BYTES_TO_STR,
-            TRANSMUTE_INT_TO_BOOL,
-            TRANSMUTE_INT_TO_FLOAT,
-        )
-    }
-}
+declare_lint_pass!(Transmute => [
+    CROSSPOINTER_TRANSMUTE,
+    TRANSMUTE_PTR_TO_REF,
+    TRANSMUTE_PTR_TO_PTR,
+    USELESS_TRANSMUTE,
+    WRONG_TRANSMUTE,
+    TRANSMUTE_INT_TO_CHAR,
+    TRANSMUTE_BYTES_TO_STR,
+    TRANSMUTE_INT_TO_BOOL,
+    TRANSMUTE_INT_TO_FLOAT,
+]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
+    #[allow(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
         if let ExprKind::Call(ref path_expr, ref args) = e.node {
             if let ExprKind::Path(ref qpath) = path_expr.node {
-                if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path_expr.hir_id)) {
-                    if match_def_path(cx.tcx, def_id, &paths::TRANSMUTE) {
+                if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
+                    if match_def_path(cx, def_id, &*paths::TRANSMUTE) {
                         let from_ty = cx.tables.expr_ty(&args[0]);
                         let to_ty = cx.tables.expr_ty(e);
 
@@ -231,72 +232,79 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                 e.span,
                                 &format!("transmute from a type (`{}`) to itself", from_ty),
                             ),
-                            (&ty::TyRef(_, rty, rty_mutbl), &ty::TyRawPtr(ptr_ty)) => span_lint_and_then(
+                            (&ty::Ref(_, rty, rty_mutbl), &ty::RawPtr(ptr_ty)) => span_lint_and_then(
                                 cx,
                                 USELESS_TRANSMUTE,
                                 e.span,
                                 "transmute from a reference to a pointer",
-                                |db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
-                                    let rty_and_mut = ty::TypeAndMut { ty: rty, mutbl: rty_mutbl };
+                                |db| {
+                                    if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                                        let rty_and_mut = ty::TypeAndMut {
+                                            ty: rty,
+                                            mutbl: rty_mutbl,
+                                        };
 
-                                    let sugg = if ptr_ty == rty_and_mut {
-                                        arg.as_ty(to_ty)
-                                    } else {
-                                        arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty)
-                                    };
+                                        let sugg = if ptr_ty == rty_and_mut {
+                                            arg.as_ty(to_ty)
+                                        } else {
+                                            arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty)
+                                        };
 
-                                    db.span_suggestion(e.span, "try", sugg.to_string());
+                                        db.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
+                                    }
                                 },
                             ),
-                            (&ty::TyInt(_), &ty::TyRawPtr(_)) | (&ty::TyUint(_), &ty::TyRawPtr(_)) => {
-                                span_lint_and_then(
-                                    cx,
-                                    USELESS_TRANSMUTE,
-                                    e.span,
-                                    "transmute from an integer to a pointer",
-                                    |db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
-                                        db.span_suggestion(e.span, "try", arg.as_ty(&to_ty.to_string()).to_string());
-                                    },
-                                )
-                            },
-                            (&ty::TyFloat(_), &ty::TyRef(..)) |
-                            (&ty::TyFloat(_), &ty::TyRawPtr(_)) |
-                            (&ty::TyChar, &ty::TyRef(..)) |
-                            (&ty::TyChar, &ty::TyRawPtr(_)) => span_lint(
+                            (&ty::Int(_), &ty::RawPtr(_)) | (&ty::Uint(_), &ty::RawPtr(_)) => span_lint_and_then(
+                                cx,
+                                USELESS_TRANSMUTE,
+                                e.span,
+                                "transmute from an integer to a pointer",
+                                |db| {
+                                    if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                                        db.span_suggestion(
+                                            e.span,
+                                            "try",
+                                            arg.as_ty(&to_ty.to_string()).to_string(),
+                                            Applicability::Unspecified,
+                                        );
+                                    }
+                                },
+                            ),
+                            (&ty::Float(_), &ty::Ref(..))
+                            | (&ty::Float(_), &ty::RawPtr(_))
+                            | (&ty::Char, &ty::Ref(..))
+                            | (&ty::Char, &ty::RawPtr(_)) => span_lint(
                                 cx,
                                 WRONG_TRANSMUTE,
                                 e.span,
                                 &format!("transmute from a `{}` to a pointer", from_ty),
                             ),
-                            (&ty::TyRawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
+                            (&ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
                                 cx,
                                 CROSSPOINTER_TRANSMUTE,
                                 e.span,
                                 &format!(
                                     "transmute from a type (`{}`) to the type that it points to (`{}`)",
-                                    from_ty,
-                                    to_ty
+                                    from_ty, to_ty
                                 ),
                             ),
-                            (_, &ty::TyRawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint(
+                            (_, &ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint(
                                 cx,
                                 CROSSPOINTER_TRANSMUTE,
                                 e.span,
                                 &format!(
                                     "transmute from a type (`{}`) to a pointer to that type (`{}`)",
-                                    from_ty,
-                                    to_ty
+                                    from_ty, to_ty
                                 ),
                             ),
-                            (&ty::TyRawPtr(from_pty), &ty::TyRef(_, to_ref_ty, mutbl)) => span_lint_and_then(
+                            (&ty::RawPtr(from_pty), &ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then(
                                 cx,
                                 TRANSMUTE_PTR_TO_REF,
                                 e.span,
                                 &format!(
                                     "transmute from a pointer type (`{}`) to a reference type \
                                      (`{}`)",
-                                    from_ty,
-                                    to_ty
+                                    from_ty, to_ty
                                 ),
                                 |db| {
                                     let arg = sugg::Sugg::hir(cx, &args[0], "..");
@@ -312,33 +320,40 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                         arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty)))
                                     };
 
-                                    db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string());
-                                },
-                            ),
-                            (&ty::TyInt(ast::IntTy::I32), &ty::TyChar) |
-                            (&ty::TyUint(ast::UintTy::U32), &ty::TyChar) => span_lint_and_then(
-                                cx,
-                                TRANSMUTE_INT_TO_CHAR,
-                                e.span,
-                                &format!("transmute from a `{}` to a `char`", from_ty),
-                                |db| {
-                                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
-                                    let arg = if let ty::TyInt(_) = from_ty.sty {
-                                        arg.as_ty(ty::TyUint(ast::UintTy::U32))
-                                    } else {
-                                        arg
-                                    };
                                     db.span_suggestion(
                                         e.span,
-                                        "consider using",
-                                        format!("std::char::from_u32({}).unwrap()", arg.to_string()),
+                                        "try",
+                                        sugg::make_unop(deref, arg).to_string(),
+                                        Applicability::Unspecified,
                                     );
                                 },
                             ),
-                            (&ty::TyRef(_, ty_from, from_mutbl), &ty::TyRef(_, ty_to, to_mutbl)) => {
+                            (&ty::Int(ast::IntTy::I32), &ty::Char) | (&ty::Uint(ast::UintTy::U32), &ty::Char) => {
+                                span_lint_and_then(
+                                    cx,
+                                    TRANSMUTE_INT_TO_CHAR,
+                                    e.span,
+                                    &format!("transmute from a `{}` to a `char`", from_ty),
+                                    |db| {
+                                        let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                                        let arg = if let ty::Int(_) = from_ty.sty {
+                                            arg.as_ty(ast::UintTy::U32)
+                                        } else {
+                                            arg
+                                        };
+                                        db.span_suggestion(
+                                            e.span,
+                                            "consider using",
+                                            format!("std::char::from_u32({}).unwrap()", arg.to_string()),
+                                            Applicability::Unspecified,
+                                        );
+                                    },
+                                )
+                            },
+                            (&ty::Ref(_, ty_from, from_mutbl), &ty::Ref(_, ty_to, to_mutbl)) => {
                                 if_chain! {
-                                    if let (&ty::TySlice(slice_ty), &ty::TyStr) = (&ty_from.sty, &ty_to.sty);
-                                    if let ty::TyUint(ast::UintTy::U8) = slice_ty.sty;
+                                    if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.sty, &ty_to.sty);
+                                    if let ty::Uint(ast::UintTy::U8) = slice_ty.sty;
                                     if from_mutbl == to_mutbl;
                                     then {
                                         let postfix = if from_mutbl == Mutability::MutMutable {
@@ -361,6 +376,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                                         postfix,
                                                         snippet(cx, args[0].span, ".."),
                                                     ),
+                                                    Applicability::Unspecified,
                                                 );
                                             }
                                         )
@@ -372,32 +388,44 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                                 e.span,
                                                 "transmute from a reference to a reference",
                                                 |db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
-                                                    let ty_from_and_mut = ty::TypeAndMut { ty: ty_from, mutbl: from_mutbl };
+                                                    let ty_from_and_mut = ty::TypeAndMut {
+                                                        ty: ty_from,
+                                                        mutbl: from_mutbl
+                                                    };
                                                     let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl };
-                                                    let sugg_paren = arg.as_ty(cx.tcx.mk_ptr(ty_from_and_mut)).as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
+                                                    let sugg_paren = arg
+                                                        .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
+                                                        .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
                                                     let sugg = if to_mutbl == Mutability::MutMutable {
                                                         sugg_paren.mut_addr_deref()
                                                     } else {
                                                         sugg_paren.addr_deref()
                                                     };
-                                                    db.span_suggestion(e.span, "try", sugg.to_string());
+                                                    db.span_suggestion(
+                                                        e.span,
+                                                        "try",
+                                                        sugg.to_string(),
+                                                        Applicability::Unspecified,
+                                                    );
                                                 },
                                             )
                                         }
                                     }
                                 }
                             },
-                            (&ty::TyRawPtr(_), &ty::TyRawPtr(to_ty)) => span_lint_and_then(
+                            (&ty::RawPtr(_), &ty::RawPtr(to_ty)) => span_lint_and_then(
                                 cx,
                                 TRANSMUTE_PTR_TO_PTR,
                                 e.span,
                                 "transmute from a pointer to a pointer",
-                                |db| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
-                                    let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty));
-                                    db.span_suggestion(e.span, "try", sugg.to_string());
+                                |db| {
+                                    if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                                        let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty));
+                                        db.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
+                                    }
                                 },
                             ),
-                            (&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => {
+                            (&ty::Int(ast::IntTy::I8), &ty::Bool) | (&ty::Uint(ast::UintTy::U8), &ty::Bool) => {
                                 span_lint_and_then(
                                     cx,
                                     TRANSMUTE_INT_TO_BOOL,
@@ -410,36 +438,34 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
                                             e.span,
                                             "consider using",
                                             sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string(),
+                                            Applicability::Unspecified,
                                         );
                                     },
                                 )
                             },
-                            (&ty::TyInt(_), &ty::TyFloat(_)) | (&ty::TyUint(_), &ty::TyFloat(_)) => {
-                                span_lint_and_then(
-                                    cx,
-                                    TRANSMUTE_INT_TO_FLOAT,
-                                    e.span,
-                                    &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
-                                    |db| {
-                                        let arg = sugg::Sugg::hir(cx, &args[0], "..");
-                                        let arg = if let ty::TyInt(int_ty) = from_ty.sty {
-                                            arg.as_ty(format!(
-                                                "u{}",
-                                                int_ty
-                                                    .bit_width()
-                                                    .map_or_else(|| "size".to_string(), |v| v.to_string())
-                                            ))
-                                        } else {
-                                            arg
-                                        };
-                                        db.span_suggestion(
-                                            e.span,
-                                            "consider using",
-                                            format!("{}::from_bits({})", to_ty, arg.to_string()),
-                                        );
-                                    },
-                                )
-                            },
+                            (&ty::Int(_), &ty::Float(_)) | (&ty::Uint(_), &ty::Float(_)) => span_lint_and_then(
+                                cx,
+                                TRANSMUTE_INT_TO_FLOAT,
+                                e.span,
+                                &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+                                |db| {
+                                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                                    let arg = if let ty::Int(int_ty) = from_ty.sty {
+                                        arg.as_ty(format!(
+                                            "u{}",
+                                            int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string())
+                                        ))
+                                    } else {
+                                        arg
+                                    };
+                                    db.span_suggestion(
+                                        e.span,
+                                        "consider using",
+                                        format!("{}::from_bits({})", to_ty, arg.to_string()),
+                                        Applicability::Unspecified,
+                                    );
+                                },
+                            ),
                             _ => return,
                         };
                     }
@@ -449,7 +475,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
     }
 }
 
-/// Get the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is
+/// Gets the snippet of `Bar` in `…::transmute<Foo, &Bar>`. If that snippet is
 /// not available , use
 /// the type's `ToString` implementation. In weird cases it could lead to types
 /// with invalid `'_`
@@ -461,7 +487,7 @@ fn get_type_snippet(cx: &LateContext<'_, '_>, path: &QPath, to_ref_ty: Ty<'_>) -
         if !params.parenthesized;
         if let Some(to_ty) = params.args.iter().filter_map(|arg| match arg {
             GenericArg::Type(ty) => Some(ty),
-            GenericArg::Lifetime(_) => None,
+            _ => None,
         }).nth(1);
         if let TyKind::Rptr(_, ref to_ty) = to_ty.node;
         then {
diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs
new file mode 100644 (file)
index 0000000..90623d5
--- /dev/null
@@ -0,0 +1,101 @@
+use crate::consts::{constant_context, Constant};
+use crate::utils::{match_qpath, paths, span_lint};
+use if_chain::if_chain;
+use rustc::hir::{Expr, ExprKind};
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::ast::LitKind;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for transmute calls which would receive a null pointer.
+    ///
+    /// **Why is this bad?** Transmuting a null pointer is undefined behavior.
+    ///
+    /// **Known problems:** Not all cases can be detected at the moment of this writing.
+    /// For example, variables which hold a null pointer and are then fed to a `transmute`
+    /// call, aren't detectable yet.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+    /// ```
+    pub TRANSMUTING_NULL,
+    correctness,
+    "transmutes from a null pointer to a reference, which is undefined behavior"
+}
+
+declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]);
+
+const LINT_MSG: &str = "transmuting a known null pointer into a reference.";
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TransmutingNull {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if in_external_macro(cx.sess(), expr.span) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Call(ref func, ref args) = expr.node;
+            if let ExprKind::Path(ref path) = func.node;
+            if match_qpath(path, &*paths::STD_MEM_TRANSMUTE);
+            if args.len() == 1;
+
+            then {
+
+                // Catching transmute over constants that resolve to `null`.
+                let mut const_eval_context = constant_context(cx, cx.tables);
+                if_chain! {
+                    if let ExprKind::Path(ref _qpath) = args[0].node;
+                    let x = const_eval_context.expr(&args[0]);
+                    if let Some(constant) = x;
+                    if let Constant::RawPtr(ptr_value) = constant;
+                    if ptr_value == 0;
+                    then {
+                        span_lint(
+                            cx,
+                            TRANSMUTING_NULL,
+                            expr.span,
+                            LINT_MSG)
+                    }
+                }
+
+                // Catching:
+                // `std::mem::transmute(0 as *const i32)`
+                if_chain! {
+                    if let ExprKind::Cast(ref inner_expr, ref _cast_ty) = args[0].node;
+                    if let ExprKind::Lit(ref lit) = inner_expr.node;
+                    if let LitKind::Int(0, _) = lit.node;
+                    then {
+                        span_lint(
+                            cx,
+                            TRANSMUTING_NULL,
+                            expr.span,
+                            LINT_MSG)
+                    }
+                }
+
+                // Catching:
+                // `std::mem::transmute(std::ptr::null::<i32>())`
+                if_chain! {
+                    if let ExprKind::Call(ref func1, ref args1) = args[0].node;
+                    if let ExprKind::Path(ref path1) = func1.node;
+                    if match_qpath(path1, &*paths::STD_PTR_NULL);
+                    if args1.len() == 0;
+                    then {
+                        span_lint(
+                            cx,
+                            TRANSMUTING_NULL,
+                            expr.span,
+                            LINT_MSG)
+                    }
+                }
+
+                // FIXME:
+                // Also catch transmutations of variables which are known nulls.
+                // To do this, MIR const propagation seems to be the better tool.
+                // Whenever MIR const prop routines are more developed, this will
+                // become available. As of this writing (25/03/19) it is not yet.
+            }
+        }
+    }
+}
index 6a048b1921384b87af6f201cd32d1e132233b2a2..3dffcc7361bf75b4bf8177941b7d113ed66bd761 100644 (file)
@@ -1,53 +1,54 @@
 use std::cmp;
 
+use crate::utils::sym;
+use crate::utils::{in_macro_or_desugar, is_copy, is_self_ty, snippet, span_lint_and_sugg};
+use if_chain::if_chain;
 use matches::matches;
-use rustc::hir::*;
-use rustc::hir::map::*;
+use rustc::hir;
 use rustc::hir::intravisit::FnKind;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use rustc::ty::TypeVariants;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::session::config::Config as SessionConfig;
-use rustc_target::spec::abi::Abi;
+use rustc::ty::{self, FnSig};
+use rustc::{declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
 use rustc_target::abi::LayoutOf;
-use syntax::ast::NodeId;
+use rustc_target::spec::abi::Abi;
 use syntax_pos::Span;
-use crate::utils::{in_macro, is_copy, is_self, span_lint_and_sugg, snippet};
-
-/// **What it does:** Checks for functions taking arguments by reference, where
-/// the argument type is `Copy` and small enough to be more efficient to always
-/// pass by value.
-///
-/// **Why is this bad?** In many calling conventions instances of structs will
-/// be passed through registers if they fit into two or less general purpose
-/// registers.
-///
-/// **Known problems:** This lint is target register size dependent, it is
-/// limited to 32-bit to try and reduce portability problems between 32 and
-/// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
-/// will be different.
-///
-/// The configuration option `trivial_copy_size_limit` can be set to override
-/// this limit for a project.
-///
-/// This lint attempts to allow passing arguments by reference if a reference
-/// to that argument is returned. This is implemented by comparing the lifetime
-/// of the argument and return value for equality. However, this can cause
-/// false positives in cases involving multiple lifetimes that are bounded by
-/// each other.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(v: &u32) {
-///     assert_eq!(v, 42);
-/// }
-/// // should be
-/// fn foo(v: u32) {
-///     assert_eq!(v, 42);
-/// }
-/// ```
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for functions taking arguments by reference, where
+    /// the argument type is `Copy` and small enough to be more efficient to always
+    /// pass by value.
+    ///
+    /// **Why is this bad?** In many calling conventions instances of structs will
+    /// be passed through registers if they fit into two or less general purpose
+    /// registers.
+    ///
+    /// **Known problems:** This lint is target register size dependent, it is
+    /// limited to 32-bit to try and reduce portability problems between 32 and
+    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
+    /// will be different.
+    ///
+    /// The configuration option `trivial_copy_size_limit` can be set to override
+    /// this limit for a project.
+    ///
+    /// This lint attempts to allow passing arguments by reference if a reference
+    /// to that argument is returned. This is implemented by comparing the lifetime
+    /// of the argument and return value for equality. However, this can cause
+    /// false positives in cases involving multiple lifetimes that are bounded by
+    /// each other.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo(v: &u32) {
+    ///     assert_eq!(v, 42);
+    /// }
+    /// // should be
+    /// fn foo(v: u32) {
+    ///     assert_eq!(v, 42);
+    /// }
+    /// ```
     pub TRIVIALLY_COPY_PASS_BY_REF,
     perf,
     "functions taking small copyable arguments by reference"
@@ -57,7 +58,7 @@ pub struct TriviallyCopyPassByRef {
     limit: u64,
 }
 
-impl TriviallyCopyPassByRef {
+impl<'a, 'tcx> TriviallyCopyPassByRef {
     pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
         let limit = limit.unwrap_or_else(|| {
             let bit_width = target.usize_ty.bit_width().expect("usize should have a width") as u64;
@@ -70,25 +71,95 @@ pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
         });
         Self { limit }
     }
-}
 
-impl LintPass for TriviallyCopyPassByRef {
-    fn get_lints(&self) -> LintArray {
-        lint_array![TRIVIALLY_COPY_PASS_BY_REF]
+    fn check_trait_method(&mut self, cx: &LateContext<'_, 'tcx>, item: &TraitItemRef) {
+        let method_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.id.hir_id);
+        let method_sig = cx.tcx.fn_sig(method_def_id);
+        let method_sig = cx.tcx.erase_late_bound_regions(&method_sig);
+
+        let decl = match cx.tcx.hir().fn_decl_by_hir_id(item.id.hir_id) {
+            Some(b) => b,
+            None => return,
+        };
+
+        self.check_poly_fn(cx, &decl, &method_sig, None);
+    }
+
+    fn check_poly_fn(&mut self, cx: &LateContext<'_, 'tcx>, decl: &FnDecl, sig: &FnSig<'tcx>, span: Option<Span>) {
+        // Use lifetimes to determine if we're returning a reference to the
+        // argument. In that case we can't switch to pass-by-value as the
+        // argument will not live long enough.
+        let output_lts = match sig.output().sty {
+            ty::Ref(output_lt, _, _) => vec![output_lt],
+            ty::Adt(_, substs) => substs.regions().collect(),
+            _ => vec![],
+        };
+
+        for (input, &ty) in decl.inputs.iter().zip(sig.inputs()) {
+            // All spans generated from a proc-macro invocation are the same...
+            match span {
+                Some(s) if s == input.span => return,
+                _ => (),
+            }
+
+            if_chain! {
+                if let ty::Ref(input_lt, ty, Mutability::MutImmutable) = ty.sty;
+                if !output_lts.contains(&input_lt);
+                if is_copy(cx, ty);
+                if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
+                if size <= self.limit;
+                if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.node;
+                then {
+                    let value_type = if is_self_ty(decl_ty) {
+                        "self".into()
+                    } else {
+                        snippet(cx, decl_ty.span, "_").into()
+                    };
+                    span_lint_and_sugg(
+                        cx,
+                        TRIVIALLY_COPY_PASS_BY_REF,
+                        input.span,
+                        "this argument is passed by reference, but would be more efficient if passed by value",
+                        "consider passing by value instead",
+                        value_type,
+                        Applicability::Unspecified,
+                    );
+                }
+            }
+        }
+    }
+
+    fn check_trait_items(&mut self, cx: &LateContext<'_, '_>, trait_items: &[TraitItemRef]) {
+        for item in trait_items {
+            if let AssociatedItemKind::Method { .. } = item.kind {
+                self.check_trait_method(cx, item);
+            }
+        }
     }
 }
 
+impl_lint_pass!(TriviallyCopyPassByRef => [TRIVIALLY_COPY_PASS_BY_REF]);
+
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef {
+    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
+        if in_macro_or_desugar(item.span) {
+            return;
+        }
+        if let ItemKind::Trait(_, _, _, _, ref trait_items) = item.node {
+            self.check_trait_items(cx, trait_items);
+        }
+    }
+
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
         kind: FnKind<'tcx>,
         decl: &'tcx FnDecl,
-        body: &'tcx Body,
+        _body: &'tcx Body,
         span: Span,
-        node_id: NodeId,
+        hir_id: HirId,
     ) {
-        if in_macro(span) {
+        if in_macro_or_desugar(span) {
             return;
         }
 
@@ -98,7 +169,7 @@ fn check_fn(
                     return;
                 }
                 for a in attrs {
-                    if a.meta_item_list().is_some() && a.name() == "proc_macro_derive" {
+                    if a.meta_item_list().is_some() && a.check_name(*sym::proc_macro_derive) {
                         return;
                     }
                 }
@@ -108,7 +179,11 @@ fn check_fn(
         }
 
         // Exclude non-inherent impls
-        if let Some(NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent_node(node_id)) {
+        if let Some(Node::Item(item)) = cx
+            .tcx
+            .hir()
+            .find_by_hir_id(cx.tcx.hir().get_parent_node_by_hir_id(hir_id))
+        {
             if matches!(item.node, ItemKind::Impl(_, _, _, _, Some(_), _, _) |
                 ItemKind::Trait(..))
             {
@@ -116,48 +191,11 @@ fn check_fn(
             }
         }
 
-        let fn_def_id = cx.tcx.hir.local_def_id(node_id);
+        let fn_def_id = cx.tcx.hir().local_def_id_from_hir_id(hir_id);
 
         let fn_sig = cx.tcx.fn_sig(fn_def_id);
         let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);
 
-        // Use lifetimes to determine if we're returning a reference to the
-        // argument. In that case we can't switch to pass-by-value as the
-        // argument will not live long enough.
-        let output_lt = if let TypeVariants::TyRef(output_lt, _, _) = fn_sig.output().sty {
-            Some(output_lt)
-        } else {
-            None
-        };
-
-        for ((input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments) {
-            // All spans generated from a proc-macro invocation are the same...
-            if span == input.span {
-                return;
-            }
-
-            if_chain! {
-                if let TypeVariants::TyRef(input_lt, ty, Mutability::MutImmutable) = ty.sty;
-                if Some(input_lt) != output_lt;
-                if is_copy(cx, ty);
-                if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
-                if size <= self.limit;
-                if let TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.node;
-                then {
-                    let value_type = if is_self(arg) {
-                        "self".into()
-                    } else {
-                        snippet(cx, decl_ty.span, "_").into()
-                    };
-                    span_lint_and_sugg(
-                        cx,
-                        TRIVIALLY_COPY_PASS_BY_REF,
-                        input.span,
-                        "this argument is passed by reference, but would be more efficient if passed by value",
-                        "consider passing by value instead",
-                        value_type);
-                }
-            }
-        }
+        self.check_poly_fn(cx, decl, &fn_sig, Some(span));
     }
 }
index 7b3f6f20fc74919ec5024a9d32076c870e9d3251..cf637ceb70686d13ebebd4adf37c49ff3b9472e8 100644 (file)
-use crate::reexport::*;
+#![allow(default_hash_types)]
+
+use std::borrow::Cow;
+use std::cmp::Ordering;
+use std::collections::BTreeMap;
+
+use if_chain::if_chain;
 use rustc::hir;
-use rustc::hir::*;
 use rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use if_chain::if_chain;
-use rustc::ty::{self, Ty, TyCtxt, TypeckTables};
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty::layout::LayoutOf;
+use rustc::ty::{self, InferTy, Ty, TyCtxt, TypeckTables};
+use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_errors::Applicability;
+use rustc_target::spec::abi::Abi;
 use rustc_typeck::hir_ty_to_ty;
-use std::cmp::Ordering;
-use std::collections::BTreeMap;
-use std::borrow::Cow;
 use syntax::ast::{FloatTy, IntTy, UintTy};
-use syntax::codemap::Span;
 use syntax::errors::DiagnosticBuilder;
-use crate::utils::{comparisons, differing_macro_contexts, higher, in_constant, in_macro, last_path_segment, match_def_path, match_path,
-            match_type, multispan_sugg, opt_def_id, same_tys, snippet, snippet_opt, span_help_and_lint, span_lint,
-            span_lint_and_sugg, span_lint_and_then, clip, unsext, sext, int_bits};
-use crate::utils::paths;
-use crate::consts::{constant, Constant};
+use syntax::source_map::Span;
+use syntax::symbol::Symbol;
 
-/// Handles all the linting of funky types
-#[allow(missing_copy_implementations)]
-pub struct TypePass;
+use crate::consts::{constant, Constant};
+use crate::utils::paths;
+use crate::utils::sym;
+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,
+    span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, unsext,
+};
 
-/// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
-///
-/// **Why is this bad?** `Vec` already keeps its contents in a separate area on
-/// the heap. So if you `Box` it, you just add another level of indirection
-/// without any benefit whatsoever.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct X {
-///     values: Box<Vec<Foo>>,
-/// }
-/// ```
-///
-/// Better:
-///
-/// ```rust
-/// struct X {
-///     values: Vec<Foo>,
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for use of `Box<Vec<_>>` anywhere in the code.
+    ///
+    /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
+    /// the heap. So if you `Box` it, you just add another level of indirection
+    /// without any benefit whatsoever.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// struct X {
+    ///     values: Box<Vec<Foo>>,
+    /// }
+    /// ```
+    ///
+    /// Better:
+    ///
+    /// ```rust,ignore
+    /// struct X {
+    ///     values: Vec<Foo>,
+    /// }
+    /// ```
     pub BOX_VEC,
     perf,
     "usage of `Box<Vec<T>>`, vector elements are already on the heap"
 }
 
-/// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
-/// definitions
-///
-/// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
-/// represents an optional optional value which is logically the same thing as an optional
-/// value but has an unneeded extra level of wrapping.
-///
-/// **Known problems:** None.
-///
-/// **Example**
-/// ```rust
-/// fn x() -> Option<Option<u32>> {
-///     None
-/// }
 declare_clippy_lint! {
+    /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
+    ///
+    /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
+    /// the heap. So if you `Box` its contents, you just add another level of indirection.
+    ///
+    /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see #3530,
+    /// 1st comment).
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct X {
+    ///     values: Vec<Box<i32>>,
+    /// }
+    /// ```
+    ///
+    /// Better:
+    ///
+    /// ```rust
+    /// struct X {
+    ///     values: Vec<i32>,
+    /// }
+    /// ```
+    pub VEC_BOX,
+    complexity,
+    "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
+    /// definitions
+    ///
+    /// **Why is this bad?** `Option<_>` represents an optional value. `Option<Option<_>>`
+    /// represents an optional optional value which is logically the same thing as an optional
+    /// value but has an unneeded extra level of wrapping.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example**
+    /// ```rust
+    /// fn x() -> Option<Option<u32>> {
+    ///     None
+    /// }
+    /// ```
     pub OPTION_OPTION,
     complexity,
     "usage of `Option<Option<T>>`"
 }
 
-/// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
-/// `Vec` or a `VecDeque` (formerly called `RingBuf`).
-///
-/// **Why is this bad?** Gankro says:
-///
-/// > The TL;DR of `LinkedList` is that it's built on a massive amount of
-/// pointers and indirection.
-/// > It wastes memory, it has terrible cache locality, and is all-around slow.
-/// `RingBuf`, while
-/// > "only" amortized for push/pop, should be faster in the general case for
-/// almost every possible
-/// > workload, and isn't even amortized at all if you can predict the capacity
-/// you need.
-/// >
-/// > `LinkedList`s are only really good if you're doing a lot of merging or
-/// splitting of lists.
-/// > This is because they can just mangle some pointers instead of actually
-/// copying the data. Even
-/// > if you're doing a lot of insertion in the middle of the list, `RingBuf`
-/// can still be better
-/// > because of how expensive it is to seek to the middle of a `LinkedList`.
-///
-/// **Known problems:** False positives – the instances where using a
-/// `LinkedList` makes sense are few and far between, but they can still happen.
-///
-/// **Example:**
-/// ```rust
-/// let x = LinkedList::new();
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of any `LinkedList`, suggesting to use a
+    /// `Vec` or a `VecDeque` (formerly called `RingBuf`).
+    ///
+    /// **Why is this bad?** Gankro says:
+    ///
+    /// > The TL;DR of `LinkedList` is that it's built on a massive amount of
+    /// pointers and indirection.
+    /// > It wastes memory, it has terrible cache locality, and is all-around slow.
+    /// `RingBuf`, while
+    /// > "only" amortized for push/pop, should be faster in the general case for
+    /// almost every possible
+    /// > workload, and isn't even amortized at all if you can predict the capacity
+    /// you need.
+    /// >
+    /// > `LinkedList`s are only really good if you're doing a lot of merging or
+    /// splitting of lists.
+    /// > This is because they can just mangle some pointers instead of actually
+    /// copying the data. Even
+    /// > if you're doing a lot of insertion in the middle of the list, `RingBuf`
+    /// can still be better
+    /// > because of how expensive it is to seek to the middle of a `LinkedList`.
+    ///
+    /// **Known problems:** False positives – the instances where using a
+    /// `LinkedList` makes sense are few and far between, but they can still happen.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = LinkedList::new();
+    /// ```
     pub LINKEDLIST,
     pedantic,
-    "usage of LinkedList, usually a vector is faster, or a more specialized data \
-     structure like a VecDeque"
+    "usage of LinkedList, usually a vector is faster, or a more specialized data structure like a VecDeque"
 }
 
-/// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
-///
-/// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
-/// general.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn foo(bar: &Box<T>) { ... }
-/// ```
-///
-/// Better:
-///
-/// ```rust
-/// fn foo(bar: &T) { ... }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for use of `&Box<T>` anywhere in the code.
+    ///
+    /// **Why is this bad?** Any `&Box<T>` can also be a `&T`, which is more
+    /// general.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// fn foo(bar: &Box<T>) { ... }
+    /// ```
+    ///
+    /// Better:
+    ///
+    /// ```rust,ignore
+    /// fn foo(bar: &T) { ... }
+    /// ```
     pub BORROWED_BOX,
     complexity,
     "a borrow of a boxed type"
 }
 
-impl LintPass for TypePass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(BOX_VEC, OPTION_OPTION, LINKEDLIST, BORROWED_BOX)
-    }
-}
+declare_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypePass {
-    fn check_fn(&mut self, cx: &LateContext<'_, '_>, _: FnKind<'_>, decl: &FnDecl, _: &Body, _: Span, id: NodeId) {
-        // skip trait implementations, see #605
-        if let Some(map::NodeItem(item)) = cx.tcx.hir.find(cx.tcx.hir.get_parent(id)) {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
+    fn check_fn(&mut self, cx: &LateContext<'_, '_>, _: FnKind<'_>, decl: &FnDecl, _: &Body, _: Span, id: HirId) {
+        // Skip trait implementations; see issue #605.
+        if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_hir_id(cx.tcx.hir().get_parent_item(id)) {
             if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.node {
                 return;
             }
@@ -149,7 +178,7 @@ fn check_fn(&mut self, cx: &LateContext<'_, '_>, _: FnKind<'_>, decl: &FnDecl, _
         check_fn_decl(cx, decl);
     }
 
-    fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &StructField) {
+    fn check_struct_field(&mut self, cx: &LateContext<'_, '_>, field: &hir::StructField) {
         check_ty(cx, &field.ty, false);
     }
 
@@ -178,19 +207,19 @@ fn check_fn_decl(cx: &LateContext<'_, '_>, decl: &FnDecl) {
     }
 }
 
-/// Check if `qpath` has last segment with type parameter matching `path`
-fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str]) -> bool {
+/// Checks if `qpath` has last segment with type parameter matching `path`
+fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[Symbol]) -> bool {
     let last = last_path_segment(qpath);
     if_chain! {
         if let Some(ref params) = last.args;
         if !params.parenthesized;
         if let Some(ty) = params.args.iter().find_map(|arg| match arg {
             GenericArg::Type(ty) => Some(ty),
-            GenericArg::Lifetime(_) => None,
+            _ => None,
         });
         if let TyKind::Path(ref qpath) = ty.node;
-        if let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(ty.id)));
-        if match_def_path(cx.tcx, did, path);
+        if let Some(did) = cx.tables.qpath_res(qpath, ty.hir_id).opt_def_id();
+        if match_def_path(cx, did, path);
         then {
             return true;
         }
@@ -203,42 +232,78 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath, path: &[&str])
 ///
 /// The parameter `is_local` distinguishes the context of the type; types from
 /// local bindings should only be checked for the `BORROWED_BOX` lint.
-fn check_ty(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool) {
-    if in_macro(ast_ty.span) {
+#[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) {
         return;
     }
-    match ast_ty.node {
+    match hir_ty.node {
         TyKind::Path(ref qpath) if !is_local => {
-            let hir_id = cx.tcx.hir.node_to_hir_id(ast_ty.id);
-            let def = cx.tables.qpath_def(qpath, hir_id);
-            if let Some(def_id) = opt_def_id(def) {
+            let hir_id = hir_ty.hir_id;
+            let res = cx.tables.qpath_res(qpath, hir_id);
+            if let Some(def_id) = res.opt_def_id() {
                 if Some(def_id) == cx.tcx.lang_items().owned_box() {
-                    if match_type_parameter(cx, qpath, &paths::VEC) {
+                    if match_type_parameter(cx, qpath, &*paths::VEC) {
                         span_help_and_lint(
                             cx,
                             BOX_VEC,
-                            ast_ty.span,
+                            hir_ty.span,
                             "you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
                             "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
                         );
                         return; // don't recurse into the type
                     }
-                } else if match_def_path(cx.tcx, def_id, &paths::OPTION) {
-                    if match_type_parameter(cx, qpath, &paths::OPTION) {
+                } else if match_def_path(cx, def_id, &*paths::VEC) {
+                    if_chain! {
+                        // Get the _ part of Vec<_>
+                        if let Some(ref last) = last_path_segment(qpath).args;
+                        if let Some(ty) = last.args.iter().find_map(|arg| match arg {
+                            GenericArg::Type(ty) => Some(ty),
+                            _ => None,
+                        });
+                        // ty is now _ at this point
+                        if let TyKind::Path(ref ty_qpath) = ty.node;
+                        let res = cx.tables.qpath_res(ty_qpath, ty.hir_id);
+                        if let Some(def_id) = res.opt_def_id();
+                        if Some(def_id) == cx.tcx.lang_items().owned_box();
+                        // At this point, we know ty is Box<T>, now get T
+                        if let Some(ref last) = last_path_segment(ty_qpath).args;
+                        if let Some(boxed_ty) = last.args.iter().find_map(|arg| match arg {
+                            GenericArg::Type(ty) => Some(ty),
+                            _ => None,
+                        });
+                        then {
+                            let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
+                            if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env) {
+                                span_lint_and_sugg(
+                                    cx,
+                                    VEC_BOX,
+                                    hir_ty.span,
+                                    "`Vec<T>` is already on the heap, the boxing is unnecessary.",
+                                    "try",
+                                    format!("Vec<{}>", ty_ty),
+                                    Applicability::MachineApplicable,
+                                );
+                                return; // don't recurse into the type
+                            }
+                        }
+                    }
+                } else if match_def_path(cx, def_id, &*paths::OPTION) {
+                    if match_type_parameter(cx, qpath, &*paths::OPTION) {
                         span_lint(
                             cx,
                             OPTION_OPTION,
-                            ast_ty.span,
+                            hir_ty.span,
                             "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
-                            enum if you need to distinguish all 3 cases",
+                             enum if you need to distinguish all 3 cases",
                         );
                         return; // don't recurse into the type
                     }
-                } else if match_def_path(cx.tcx, def_id, &paths::LINKED_LIST) {
+                } else if match_def_path(cx, def_id, &*paths::LINKED_LIST) {
                     span_help_and_lint(
                         cx,
                         LINKEDLIST,
-                        ast_ty.span,
+                        hir_ty.span,
                         "I see you're using a LinkedList! Perhaps you meant some other data structure?",
                         "a VecDeque might work",
                     );
@@ -254,29 +319,31 @@ enum if you need to distinguish all 3 cases",
                             .map_or_else(|| [].iter(), |params| params.args.iter())
                             .filter_map(|arg| match arg {
                                 GenericArg::Type(ty) => Some(ty),
-                                GenericArg::Lifetime(_) => None,
+                                _ => None,
                             })
                     }) {
                         check_ty(cx, ty, is_local);
                     }
                 },
-                QPath::Resolved(None, ref p) => for ty in p.segments.iter().flat_map(|seg| {
-                    seg.args
-                        .as_ref()
-                        .map_or_else(|| [].iter(), |params| params.args.iter())
-                        .filter_map(|arg| match arg {
-                            GenericArg::Type(ty) => Some(ty),
-                            GenericArg::Lifetime(_) => None,
-                        })
-                }) {
-                    check_ty(cx, ty, is_local);
+                QPath::Resolved(None, ref p) => {
+                    for ty in p.segments.iter().flat_map(|seg| {
+                        seg.args
+                            .as_ref()
+                            .map_or_else(|| [].iter(), |params| params.args.iter())
+                            .filter_map(|arg| match arg {
+                                GenericArg::Type(ty) => Some(ty),
+                                _ => None,
+                            })
+                    }) {
+                        check_ty(cx, ty, is_local);
+                    }
                 },
                 QPath::TypeRelative(ref ty, ref seg) => {
                     check_ty(cx, ty, is_local);
                     if let Some(ref params) = seg.args {
                         for ty in params.args.iter().filter_map(|arg| match arg {
                             GenericArg::Type(ty) => Some(ty),
-                            GenericArg::Lifetime(_) => None,
+                            _ => None,
                         }) {
                             check_ty(cx, ty, is_local);
                         }
@@ -284,23 +351,27 @@ enum if you need to distinguish all 3 cases",
                 },
             }
         },
-        TyKind::Rptr(ref lt, ref mut_ty) => check_ty_rptr(cx, ast_ty, is_local, lt, mut_ty),
+        TyKind::Rptr(ref lt, ref mut_ty) => check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
         // recurse
-        TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local),
-        TyKind::Tup(ref tys) => for ty in tys {
-            check_ty(cx, ty, is_local);
+        TyKind::Slice(ref ty) | TyKind::Array(ref ty, _) | TyKind::Ptr(MutTy { ref ty, .. }) => {
+            check_ty(cx, ty, is_local)
+        },
+        TyKind::Tup(ref tys) => {
+            for ty in tys {
+                check_ty(cx, ty, is_local);
+            }
         },
         _ => {},
     }
 }
 
-fn check_ty_rptr(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) {
+fn check_ty_rptr(cx: &LateContext<'_, '_>, hir_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) {
     match mut_ty.ty.node {
         TyKind::Path(ref qpath) => {
-            let hir_id = cx.tcx.hir.node_to_hir_id(mut_ty.ty.id);
-            let def = cx.tables.qpath_def(qpath, hir_id);
+            let hir_id = mut_ty.ty.hir_id;
+            let def = cx.tables.qpath_res(qpath, hir_id);
             if_chain! {
-                if let Some(def_id) = opt_def_id(def);
+                if let Some(def_id) = def.opt_def_id();
                 if Some(def_id) == cx.tcx.lang_items().owned_box();
                 if let QPath::Resolved(None, ref path) = *qpath;
                 if let [ref bx] = *path.segments;
@@ -308,30 +379,38 @@ fn check_ty_rptr(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool, lt:
                 if !params.parenthesized;
                 if let Some(inner) = params.args.iter().find_map(|arg| match arg {
                     GenericArg::Type(ty) => Some(ty),
-                    GenericArg::Lifetime(_) => None,
+                    _ => None,
                 });
                 then {
                     if is_any_trait(inner) {
-                        // Ignore `Box<Any>` types, see #1884 for details.
+                        // Ignore `Box<Any>` types; see issue #1884 for details.
                         return;
                     }
 
                     let ltopt = if lt.is_elided() {
-                        "".to_owned()
+                        String::new()
                     } else {
-                        format!("{} ", lt.name.ident().name.as_str())
+                        format!("{} ", lt.name.ident().as_str())
                     };
                     let mutopt = if mut_ty.mutbl == Mutability::MutMutable {
                         "mut "
                     } else {
                         ""
                     };
-                    span_lint_and_sugg(cx,
+                    let mut applicability = Applicability::MachineApplicable;
+                    span_lint_and_sugg(
+                        cx,
                         BORROWED_BOX,
-                        ast_ty.span,
+                        hir_ty.span,
                         "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
                         "try",
-                        format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, ".."))
+                        format!(
+                            "&{}{}{}",
+                            ltopt,
+                            mutopt,
+                            &snippet_with_applicability(cx, inner.span, "..", &mut applicability)
+                        ),
+                        Applicability::Unspecified,
                     );
                     return; // don't recurse into the type
                 }
@@ -349,7 +428,7 @@ fn is_any_trait(t: &hir::Ty) -> bool {
         if traits.len() >= 1;
         // Only Send/Sync can be used as additional traits, so it is enough to
         // check only the first trait.
-        if match_path(&traits[0].trait_ref.path, &paths::ANY_TRAIT);
+        if match_path(&traits[0].trait_ref.path, &*paths::ANY_TRAIT);
         then {
             return true;
         }
@@ -358,94 +437,94 @@ fn is_any_trait(t: &hir::Ty) -> bool {
     false
 }
 
-#[allow(missing_copy_implementations)]
-pub struct LetPass;
-
-/// **What it does:** Checks for binding a unit value.
-///
-/// **Why is this bad?** A unit value cannot usefully be used anywhere. So
-/// binding one is kind of pointless.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = { 1; };
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for binding a unit value.
+    ///
+    /// **Why is this bad?** A unit value cannot usefully be used anywhere. So
+    /// binding one is kind of pointless.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = {
+    ///     1;
+    /// };
+    /// ```
     pub LET_UNIT_VALUE,
     style,
     "creating a let binding to a value of unit type, which usually can't be used afterwards"
 }
 
-fn check_let_unit(cx: &LateContext<'_, '_>, decl: &Decl) {
-    if let DeclKind::Local(ref local) = decl.node {
-        if is_unit(cx.tables.pat_ty(&local.pat)) {
-            if in_external_macro(cx.sess(), decl.span) || in_macro(local.pat.span) {
-                return;
-            }
-            if higher::is_from_for_desugar(decl) {
-                return;
+declare_lint_pass!(LetUnitValue => [LET_UNIT_VALUE]);
+
+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) {
+                    return;
+                }
+                if higher::is_from_for_desugar(local) {
+                    return;
+                }
+                span_lint(
+                    cx,
+                    LET_UNIT_VALUE,
+                    stmt.span,
+                    &format!(
+                        "this let-binding has unit value. Consider omitting `let {} =`",
+                        snippet(cx, local.pat.span, "..")
+                    ),
+                );
             }
-            span_lint(
-                cx,
-                LET_UNIT_VALUE,
-                decl.span,
-                &format!(
-                    "this let-binding has unit value. Consider omitting `let {} =`",
-                    snippet(cx, local.pat.span, "..")
-                ),
-            );
         }
     }
 }
 
-impl LintPass for LetPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(LET_UNIT_VALUE)
-    }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetPass {
-    fn check_decl(&mut self, cx: &LateContext<'a, 'tcx>, decl: &'tcx Decl) {
-        check_let_unit(cx, decl)
-    }
-}
-
-/// **What it does:** Checks for comparisons to unit.
-///
-/// **Why is this bad?** Unit is always equal to itself, and thus is just a
-/// clumsily written constant. Mostly this happens when someone accidentally
-/// adds semicolons at the end of the operands.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// if { foo(); } == { bar(); } { baz(); }
-/// ```
-/// is equal to
-/// ```rust
-/// { foo(); bar(); baz(); }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for comparisons to unit.
+    ///
+    /// **Why is this bad?** Unit is always equal to itself, and thus is just a
+    /// clumsily written constant. Mostly this happens when someone accidentally
+    /// adds semicolons at the end of the operands.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # fn foo() {};
+    /// # fn bar() {};
+    /// # fn baz() {};
+    /// if {
+    ///     foo();
+    /// } == {
+    ///     bar();
+    /// } {
+    ///     baz();
+    /// }
+    /// ```
+    /// is equal to
+    /// ```rust
+    /// # fn foo() {};
+    /// # fn bar() {};
+    /// # fn baz() {};
+    /// {
+    ///     foo();
+    ///     bar();
+    ///     baz();
+    /// }
+    /// ```
     pub UNIT_CMP,
     correctness,
     "comparing unit values"
 }
 
-#[allow(missing_copy_implementations)]
-pub struct UnitCmp;
-
-impl LintPass for UnitCmp {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNIT_CMP)
-    }
-}
+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(expr.span) {
+        if in_macro_or_desugar(expr.span) {
             return;
         }
         if let ExprKind::Binary(ref cmp, ref left, _) = expr.node {
@@ -470,67 +549,70 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-/// **What it does:** Checks for passing a unit value as an argument to a function without using a unit literal (`()`).
-///
-/// **Why is this bad?** This is likely the result of an accidental semicolon.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// foo({
-///   let a = bar();
-///   baz(a);
-/// })
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for passing a unit value as an argument to a function without using a
+    /// unit literal (`()`).
+    ///
+    /// **Why is this bad?** This is likely the result of an accidental semicolon.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// foo({
+    ///     let a = bar();
+    ///     baz(a);
+    /// })
+    /// ```
     pub UNIT_ARG,
     complexity,
     "passing unit to a function"
 }
 
-pub struct UnitArg;
-
-impl LintPass for UnitArg {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNIT_ARG)
-    }
-}
+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(expr.span) {
+        if in_macro_or_desugar(expr.span) {
+            return;
+        }
+
+        // apparently stuff in the desugaring of `?` can trigger this
+        // so check for that here
+        // only the calls to `Try::from_error` is marked as desugared,
+        // so we need to check both the current Expr and its parent.
+        if is_questionmark_desugar_marked_call(expr) {
             return;
         }
+        if_chain! {
+            let map = &cx.tcx.hir();
+            let opt_parent_node = map.find_by_hir_id(map.get_parent_node_by_hir_id(expr.hir_id));
+            if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node;
+            if is_questionmark_desugar_marked_call(parent_expr);
+            then {
+                return;
+            }
+        }
+
         match expr.node {
             ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
                 for arg in args {
                     if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
-                        let map = &cx.tcx.hir;
-                        // apparently stuff in the desugaring of `?` can trigger this
-                        // so check for that here
-                        // only the calls to `Try::from_error` is marked as desugared,
-                        // so we need to check both the current Expr and its parent.
-                        if !is_questionmark_desugar_marked_call(expr) {
-                            if_chain!{
-                                let opt_parent_node = map.find(map.get_parent_node(expr.id));
-                                if let Some(hir::map::NodeExpr(parent_expr)) = opt_parent_node;
-                                if is_questionmark_desugar_marked_call(parent_expr);
-                                then {}
-                                else {
-                                    // `expr` and `parent_expr` where _both_ not from
-                                    // desugaring `?`, so lint
-                                    span_lint_and_sugg(
-                                        cx,
-                                        UNIT_ARG,
-                                        arg.span,
-                                        "passing a unit value to a function",
-                                        "if you intended to pass a unit value, use a unit literal instead",
-                                        "()".to_string(),
-                                    );
-                                }
+                        if let ExprKind::Match(.., match_source) = &arg.node {
+                            if *match_source == MatchSource::TryDesugar {
+                                continue;
                             }
                         }
+
+                        span_lint_and_sugg(
+                            cx,
+                            UNIT_ARG,
+                            arg.span,
+                            "passing a unit value to a function",
+                            "if you intended to pass a unit value, use a unit literal instead",
+                            "()".to_string(),
+                            Applicability::MachineApplicable,
+                        );
                     }
                 }
             },
@@ -550,7 +632,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr) -> bool {
 
 fn is_unit(ty: Ty<'_>) -> bool {
     match ty.sty {
-        ty::TyTuple(slice) if slice.is_empty() => true,
+        ty::Tuple(slice) if slice.is_empty() => true,
         _ => false,
     }
 }
@@ -562,200 +644,226 @@ fn is_unit_literal(expr: &Expr) -> bool {
     }
 }
 
-pub struct CastPass;
-
-/// **What it does:** Checks for casts from any numerical to a float type where
-/// the receiving type cannot store all values from the original type without
-/// rounding errors. This possible rounding is to be expected, so this lint is
-/// `Allow` by default.
-///
-/// Basically, this warns on casting any integer with 32 or more bits to `f32`
-/// or any 64-bit integer to `f64`.
-///
-/// **Why is this bad?** It's not bad at all. But in some applications it can be
-/// helpful to know where precision loss can take place. This lint can help find
-/// those places in the code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = u64::MAX; x as f64
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for casts from any numerical to a float type where
+    /// the receiving type cannot store all values from the original type without
+    /// rounding errors. This possible rounding is to be expected, so this lint is
+    /// `Allow` by default.
+    ///
+    /// Basically, this warns on casting any integer with 32 or more bits to `f32`
+    /// or any 64-bit integer to `f64`.
+    ///
+    /// **Why is this bad?** It's not bad at all. But in some applications it can be
+    /// helpful to know where precision loss can take place. This lint can help find
+    /// those places in the code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = u64::MAX;
+    /// x as f64
+    /// ```
     pub CAST_PRECISION_LOSS,
     pedantic,
-    "casts that cause loss of precision, e.g. `x as f32` where `x: u64`"
+    "casts that cause loss of precision, e.g., `x as f32` where `x: u64`"
 }
 
-/// **What it does:** Checks for casts from a signed to an unsigned numerical
-/// type. In this case, negative values wrap around to large positive values,
-/// which can be quite surprising in practice. However, as the cast works as
-/// defined, this lint is `Allow` by default.
-///
-/// **Why is this bad?** Possibly surprising results. You can activate this lint
-/// as a one-time check to see where numerical wrapping can arise.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let y: i8 = -1;
-/// y as u128  // will return 18446744073709551615
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for casts from a signed to an unsigned numerical
+    /// type. In this case, negative values wrap around to large positive values,
+    /// which can be quite surprising in practice. However, as the cast works as
+    /// defined, this lint is `Allow` by default.
+    ///
+    /// **Why is this bad?** Possibly surprising results. You can activate this lint
+    /// as a one-time check to see where numerical wrapping can arise.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let y: i8 = -1;
+    /// y as u128 // will return 18446744073709551615
+    /// ```
     pub CAST_SIGN_LOSS,
     pedantic,
-    "casts from signed types to unsigned types, e.g. `x as u32` where `x: i32`"
+    "casts from signed types to unsigned types, e.g., `x as u32` where `x: i32`"
 }
 
-/// **What it does:** Checks for on casts between numerical types that may
-/// truncate large values. This is expected behavior, so the cast is `Allow` by
-/// default.
-///
-/// **Why is this bad?** In some problem domains, it is good practice to avoid
-/// truncation. This lint can be activated to help assess where additional
-/// checks could be beneficial.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn as_u8(x: u64) -> u8 { x as u8 }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for on casts between numerical types that may
+    /// truncate large values. This is expected behavior, so the cast is `Allow` by
+    /// default.
+    ///
+    /// **Why is this bad?** In some problem domains, it is good practice to avoid
+    /// truncation. This lint can be activated to help assess where additional
+    /// checks could be beneficial.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn as_u8(x: u64) -> u8 {
+    ///     x as u8
+    /// }
+    /// ```
     pub CAST_POSSIBLE_TRUNCATION,
     pedantic,
-    "casts that may cause truncation of the value, e.g. `x as u8` where `x: u32`, \
-     or `x as i32` where `x: f32`"
+    "casts that may cause truncation of the value, e.g., `x as u8` where `x: u32`, or `x as i32` where `x: f32`"
 }
 
-/// **What it does:** Checks for casts from an unsigned type to a signed type of
-/// the same size. Performing such a cast is a 'no-op' for the compiler,
-/// i.e. nothing is changed at the bit level, and the binary representation of
-/// the value is reinterpreted. This can cause wrapping if the value is too big
-/// for the target signed type. However, the cast works as defined, so this lint
-/// is `Allow` by default.
-///
-/// **Why is this bad?** While such a cast is not bad in itself, the results can
-/// be surprising when this is not the intended behavior, as demonstrated by the
-/// example below.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// u32::MAX as i32  // will yield a value of `-1`
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for casts from an unsigned type to a signed type of
+    /// the same size. Performing such a cast is a 'no-op' for the compiler,
+    /// i.e., nothing is changed at the bit level, and the binary representation of
+    /// the value is reinterpreted. This can cause wrapping if the value is too big
+    /// for the target signed type. However, the cast works as defined, so this lint
+    /// is `Allow` by default.
+    ///
+    /// **Why is this bad?** While such a cast is not bad in itself, the results can
+    /// be surprising when this is not the intended behavior, as demonstrated by the
+    /// example below.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// u32::MAX as i32 // will yield a value of `-1`
+    /// ```
     pub CAST_POSSIBLE_WRAP,
     pedantic,
-    "casts that may cause wrapping around the value, e.g. `x as i32` where `x: u32` \
-     and `x > i32::MAX`"
+    "casts that may cause wrapping around the value, e.g., `x as i32` where `x: u32` and `x > i32::MAX`"
 }
 
-/// **What it does:** Checks for on casts between numerical types that may
-/// be replaced by safe conversion functions.
-///
-/// **Why is this bad?** Rust's `as` keyword will perform many kinds of
-/// conversions, including silently lossy conversions. Conversion functions such
-/// as `i32::from` will only perform lossless conversions. Using the conversion
-/// functions prevents conversions from turning into silent lossy conversions if
-/// the types of the input expressions ever change, and make it easier for
-/// people reading the code to know that the conversion is lossless.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn as_u64(x: u8) -> u64 { x as u64 }
-/// ```
-///
-/// Using `::from` would look like this:
-///
-/// ```rust
-/// fn as_u64(x: u8) -> u64 { u64::from(x) }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for on casts between numerical types that may
+    /// be replaced by safe conversion functions.
+    ///
+    /// **Why is this bad?** Rust's `as` keyword will perform many kinds of
+    /// conversions, including silently lossy conversions. Conversion functions such
+    /// as `i32::from` will only perform lossless conversions. Using the conversion
+    /// functions prevents conversions from turning into silent lossy conversions if
+    /// the types of the input expressions ever change, and make it easier for
+    /// people reading the code to know that the conversion is lossless.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn as_u64(x: u8) -> u64 {
+    ///     x as u64
+    /// }
+    /// ```
+    ///
+    /// Using `::from` would look like this:
+    ///
+    /// ```rust
+    /// fn as_u64(x: u8) -> u64 {
+    ///     u64::from(x)
+    /// }
+    /// ```
     pub CAST_LOSSLESS,
     complexity,
-    "casts using `as` that are known to be lossless, e.g. `x as u64` where `x: u8`"
+    "casts using `as` that are known to be lossless, e.g., `x as u64` where `x: u8`"
 }
 
-/// **What it does:** Checks for casts to the same type.
-///
-/// **Why is this bad?** It's just unnecessary.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let _ = 2i32 as i32
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for casts to the same type.
+    ///
+    /// **Why is this bad?** It's just unnecessary.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _ = 2i32 as i32
+    /// ```
     pub UNNECESSARY_CAST,
     complexity,
-    "cast to the same type, e.g. `x as i32` where `x: i32`"
+    "cast to the same type, e.g., `x as i32` where `x: i32`"
 }
 
-/// **What it does:** Checks for casts of a function pointer to a numeric type not enough to store address.
-///
-/// **Why is this bad?** Casting a function pointer to not eligible type could truncate the address value.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn test_fn() -> i16;
-/// let _ = test_fn as i32
-/// ```
 declare_clippy_lint! {
-    pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+    /// **What it does:** Checks for casts from a less-strictly-aligned pointer to a
+    /// more-strictly-aligned pointer
+    ///
+    /// **Why is this bad?** Dereferencing the resulting pointer may be undefined
+    /// behavior.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let _ = (&1u8 as *const u8) as *const u16;
+    /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
+    /// ```
+    pub CAST_PTR_ALIGNMENT,
     correctness,
-    "cast function pointer to the numeric type with value truncation"
+    "cast from a pointer to a more-strictly-aligned pointer"
 }
 
-/// **What it does:** Checks for casts of a function pointer to a numeric type except `usize`.
-///
-/// **Why is this bad?** Casting a function pointer to something other than `usize` is not a good style.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// fn test_fn() -> i16;
-/// let _ = test_fn as i128
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for casts of function pointers to something other than usize
+    ///
+    /// **Why is this bad?**
+    /// Casting a function pointer to anything other than usize/isize is not portable across
+    /// architectures, because you end up losing bits if the target type is too small or end up with a
+    /// bunch of extra bits that waste space and add more instructions to the final binary than
+    /// strictly necessary for the problem
+    ///
+    /// Casting to isize also doesn't make sense since there are no signed addresses.
+    ///
+    /// **Example**
+    ///
+    /// ```rust
+    /// // Bad
+    /// fn fun() -> i32 { 1 }
+    /// let a = fun as i64;
+    ///
+    /// // Good
+    /// fn fun2() -> i32 { 1 }
+    /// let a = fun2 as usize;
+    /// ```
     pub FN_TO_NUMERIC_CAST,
     style,
-    "cast function pointer to the numeric type"
+    "casting a function pointer to a numeric type other than usize"
 }
 
-/// **What it does:** Checks for casts from a less-strictly-aligned pointer to a
-/// more-strictly-aligned pointer
-///
-/// **Why is this bad?** Dereferencing the resulting pointer may be undefined
-/// behavior.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let _ = (&1u8 as *const u8) as *const u16;
-/// let _ = (&mut 1u8 as *mut u8) as *mut u16;
-/// ```
 declare_clippy_lint! {
-    pub CAST_PTR_ALIGNMENT,
-    correctness,
-    "cast from a pointer to a more-strictly-aligned pointer"
+    /// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to
+    /// store address.
+    ///
+    /// **Why is this bad?**
+    /// Such a cast discards some bits of the function's address. If this is intended, it would be more
+    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
+    /// a comment) to perform the truncation.
+    ///
+    /// **Example**
+    ///
+    /// ```rust
+    /// // Bad
+    /// fn fn1() -> i16 {
+    ///     1
+    /// };
+    /// let _ = fn1 as i32;
+    ///
+    /// // Better: Cast to usize first, then comment with the reason for the truncation
+    /// fn fn2() -> i16 {
+    ///     1
+    /// };
+    /// let fn_ptr = fn2 as usize;
+    /// let fn_ptr_truncated = fn_ptr as i32;
+    /// ```
+    pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+    style,
+    "casting a function pointer to a numeric type not wide enough to store the address"
 }
 
 /// Returns the size in bits of an integral type.
 /// Will return 0 if the type is not an int or uint variant
 fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 {
     match typ.sty {
-        ty::TyInt(i) => match i {
+        ty::Int(i) => match i {
             IntTy::Isize => tcx.data_layout.pointer_size.bits(),
             IntTy::I8 => 8,
             IntTy::I16 => 16,
@@ -763,7 +871,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 {
             IntTy::I64 => 64,
             IntTy::I128 => 128,
         },
-        ty::TyUint(i) => match i {
+        ty::Uint(i) => match i {
             UintTy::Usize => tcx.data_layout.pointer_size.bits(),
             UintTy::U8 => 8,
             UintTy::U16 => 16,
@@ -777,7 +885,7 @@ fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 {
 
 fn is_isize_or_usize(typ: Ty<'_>) -> bool {
     match typ.sty {
-        ty::TyInt(IntTy::Isize) | ty::TyUint(UintTy::Usize) => true,
+        ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => true,
         _ => false,
     }
 }
@@ -802,11 +910,7 @@ fn span_precision_loss_lint(cx: &LateContext<'_, '_>, expr: &Expr, cast_from: Ty
              is only {4} bits wide)",
             cast_from,
             if cast_to_f64 { "f64" } else { "f32" },
-            if arch_dependent {
-                arch_dependent_str
-            } else {
-                ""
-            },
+            if arch_dependent { arch_dependent_str } else { "" },
             from_nbits_str,
             mantissa_nbits
         ),
@@ -824,9 +928,12 @@ fn should_strip_parens(op: &Expr, snip: &str) -> bool {
 
 fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
-    if in_constant(cx, expr.id) { return }
+    if in_constant(cx, expr.hir_id) {
+        return;
+    }
     // The suggestion is to use a function call, so if the original expression
     // has parens on the outside, they are no longer needed.
+    let mut applicability = Applicability::MachineApplicable;
     let opt = snippet_opt(cx, op.span);
     let sugg = if let Some(ref snip) = opt {
         if should_strip_parens(op, snip) {
@@ -835,6 +942,7 @@ fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_fro
             snip.as_str()
         }
     } else {
+        applicability = Applicability::HasPlaceholders;
         ".."
     };
 
@@ -842,9 +950,13 @@ fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_fro
         cx,
         CAST_LOSSLESS,
         expr.span,
-        &format!("casting {} to {} may become silently lossy if types change", cast_from, cast_to),
+        &format!(
+            "casting {} to {} may become silently lossy if you later change the type",
+            cast_from, cast_to
+        ),
         "try",
         format!("{}::from({})", cast_to, sugg),
+        applicability,
     );
 }
 
@@ -854,6 +966,31 @@ enum ArchSuffix {
     None,
 }
 
+fn check_loss_of_sign(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+    if !cast_from.is_signed() || cast_to.is_signed() {
+        return;
+    }
+
+    // don't lint for positive constants
+    let const_val = constant(cx, &cx.tables, op);
+    if_chain! {
+        if let Some((const_val, _)) = const_val;
+        if let Constant::Int(n) = const_val;
+        if let ty::Int(ity) = cast_from.sty;
+        if sext(cx.tcx, n, ity) >= 0;
+        then {
+            return
+        }
+    }
+
+    span_lint(
+        cx,
+        CAST_SIGN_LOSS,
+        expr.span,
+        &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to),
+    );
+}
+
 fn check_truncation_and_wrapping(cx: &LateContext<'_, '_>, expr: &Expr, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     let arch_64_suffix = " on targets with 64-bit wide pointers";
     let arch_32_suffix = " on targets with 32-bit wide pointers";
@@ -935,37 +1072,86 @@ fn check_lossless(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_from: T
     }
 }
 
-impl LintPass for CastPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            CAST_PRECISION_LOSS,
-            CAST_SIGN_LOSS,
-            CAST_POSSIBLE_TRUNCATION,
-            CAST_POSSIBLE_WRAP,
-            CAST_LOSSLESS,
-            UNNECESSARY_CAST,
-            CAST_PTR_ALIGNMENT,
-            FN_TO_NUMERIC_CAST,
-            FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
-        )
+declare_lint_pass!(Casts => [
+    CAST_PRECISION_LOSS,
+    CAST_SIGN_LOSS,
+    CAST_POSSIBLE_TRUNCATION,
+    CAST_POSSIBLE_WRAP,
+    CAST_LOSSLESS,
+    UNNECESSARY_CAST,
+    CAST_PTR_ALIGNMENT,
+    FN_TO_NUMERIC_CAST,
+    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+]);
+
+// Check if the given type is either `core::ffi::c_void` or
+// one of the platform specific `libc::<platform>::c_void` of libc.
+fn is_c_void(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
+    if let ty::Adt(adt, _) = ty.sty {
+        let names = cx.get_def_path(adt.did);
+
+        if names.is_empty() {
+            return false;
+        }
+        if names[0] == "libc" || names[0] == "core" && *names.last().unwrap() == "c_void" {
+            return true;
+        }
+    }
+    false
+}
+
+/// Returns the mantissa bits wide of a fp type.
+/// Will return 0 if the type is not a fp
+fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
+    match typ.sty {
+        ty::Float(FloatTy::F32) => 23,
+        ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
+        _ => 0,
     }
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
+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) {
+            return;
+        }
         if let ExprKind::Cast(ref ex, _) = expr.node {
             let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
+            lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
             if let ExprKind::Lit(ref lit) = ex.node {
                 use syntax::ast::{LitIntType, LitKind};
+                if let LitKind::Int(n, _) = lit.node {
+                    if cast_to.is_fp() {
+                        let from_nbits = 128 - n.leading_zeros();
+                        let to_nbits = fp_ty_mantissa_nbits(cast_to);
+                        if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits {
+                            span_lint_and_sugg(
+                                cx,
+                                UNNECESSARY_CAST,
+                                expr.span,
+                                &format!("casting integer literal to {} is unnecessary", cast_to),
+                                "try",
+                                format!("{}_{}", n, cast_to),
+                                Applicability::MachineApplicable,
+                            );
+                            return;
+                        }
+                    }
+                }
                 match lit.node {
                     LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::FloatUnsuffixed(_) => {},
-                    _ => if cast_from.sty == cast_to.sty && !in_external_macro(cx.sess(), expr.span) {
-                        span_lint(
-                            cx,
-                            UNNECESSARY_CAST,
-                            expr.span,
-                            &format!("casting to the same type is unnecessary (`{}` -> `{}`)", cast_from, cast_to),
-                        );
+                    _ => {
+                        if cast_from.sty == cast_to.sty && !in_external_macro(cx.sess(), expr.span) {
+                            span_lint(
+                                cx,
+                                UNNECESSARY_CAST,
+                                expr.span,
+                                &format!(
+                                    "casting to the same type is unnecessary (`{}` -> `{}`)",
+                                    cast_from, cast_to
+                                ),
+                            );
+                        }
                     },
                 }
             }
@@ -973,7 +1159,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                 match (cast_from.is_integral(), cast_to.is_integral()) {
                     (true, false) => {
                         let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
-                        let to_nbits = if let ty::TyFloat(FloatTy::F32) = cast_to.sty {
+                        let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.sty {
                             32
                         } else {
                             64
@@ -1002,20 +1188,12 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                         }
                     },
                     (true, true) => {
-                        if cast_from.is_signed() && !cast_to.is_signed() {
-                            span_lint(
-                                cx,
-                                CAST_SIGN_LOSS,
-                                expr.span,
-                                &format!("casting {} to {} may lose the sign of the value", cast_from, cast_to),
-                            );
-                        }
+                        check_loss_of_sign(cx, expr, ex, cast_from, cast_to);
                         check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
                         check_lossless(cx, expr, ex, cast_from, cast_to);
                     },
                     (false, false) => {
-                        if let (&ty::TyFloat(FloatTy::F64), &ty::TyFloat(FloatTy::F32)) = (&cast_from.sty, &cast_to.sty)
-                        {
+                        if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.sty, &cast_to.sty) {
                             span_lint(
                                 cx,
                                 CAST_POSSIBLE_TRUNCATION,
@@ -1023,56 +1201,21 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
                                 "casting f64 to f32 may truncate the value",
                             );
                         }
-                        if let (&ty::TyFloat(FloatTy::F32), &ty::TyFloat(FloatTy::F64)) = (&cast_from.sty, &cast_to.sty)
-                        {
+                        if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.sty, &cast_to.sty) {
                             span_lossless_lint(cx, expr, ex, cast_from, cast_to);
                         }
                     },
                 }
             }
 
-            match &cast_from.sty {
-                ty::TyFnDef(..) |
-                ty::TyFnPtr(..) => {
-                    if cast_to.is_numeric() && cast_to.sty != ty::TyUint(UintTy::Usize){
-                        let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
-                        let pointer_nbits = cx.tcx.data_layout.pointer_size.bits();
-                        if to_nbits < pointer_nbits || (to_nbits == pointer_nbits && cast_to.is_signed()) {
-                            span_lint_and_sugg(
-                                cx,
-                                FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
-                                expr.span,
-                                &format!("casting a `{}` to `{}` may truncate the function address value.", cast_from, cast_to),
-                                "if you need the address of the function, consider",
-                                format!("{} as usize", &snippet(cx, ex.span, "x"))
-                            );
-                        } else {
-                            span_lint_and_sugg(
-                                cx,
-                                FN_TO_NUMERIC_CAST,
-                                expr.span,
-                                &format!("casting a `{}` to `{}` is bad style.", cast_from, cast_to),
-                                "if you need the address of the function, consider",
-                                format!("{} as usize", &snippet(cx, ex.span, "x"))
-                            );
-
-                        };
-                    }
-                }
-                _ => ()
-            }
-
-            if_chain!{
-                if let ty::TyRawPtr(from_ptr_ty) = &cast_from.sty;
-                if let ty::TyRawPtr(to_ptr_ty) = &cast_to.sty;
-                if let Some(from_align) = cx.layout_of(from_ptr_ty.ty).ok().map(|a| a.align.abi());
-                if let Some(to_align) = cx.layout_of(to_ptr_ty.ty).ok().map(|a| a.align.abi());
+            if_chain! {
+                if let ty::RawPtr(from_ptr_ty) = &cast_from.sty;
+                if let ty::RawPtr(to_ptr_ty) = &cast_to.sty;
+                if let Some(from_align) = cx.layout_of(from_ptr_ty.ty).ok().map(|a| a.align.abi);
+                if let Some(to_align) = cx.layout_of(to_ptr_ty.ty).ok().map(|a| a.align.abi);
                 if from_align < to_align;
                 // with c_void, we inherently need to trust the user
-                if ! (
-                    match_type(cx, from_ptr_ty.ty, &paths::C_VOID)
-                    || match_type(cx, from_ptr_ty.ty, &paths::C_VOID_LIBC)
-                );
+                if !is_c_void(cx, from_ptr_ty.ty);
                 then {
                     span_lint(
                         cx,
@@ -1086,44 +1229,86 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-/// **What it does:** Checks for types used in structs, parameters and `let`
-/// declarations above a certain complexity threshold.
-///
-/// **Why is this bad?** Too complex types make the code less readable. Consider
-/// using a `type` definition to simplify them.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct Foo { inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>> }
-/// ```
+fn lint_fn_to_numeric_cast(
+    cx: &LateContext<'_, '_>,
+    expr: &Expr,
+    cast_expr: &Expr,
+    cast_from: Ty<'_>,
+    cast_to: Ty<'_>,
+) {
+    // We only want to check casts to `ty::Uint` or `ty::Int`
+    match cast_to.sty {
+        ty::Uint(_) | ty::Int(..) => { /* continue on */ },
+        _ => return,
+    }
+    match cast_from.sty {
+        ty::FnDef(..) | ty::FnPtr(_) => {
+            let mut applicability = Applicability::MachineApplicable;
+            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
+
+            let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
+            if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
+                span_lint_and_sugg(
+                    cx,
+                    FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
+                    expr.span,
+                    &format!(
+                        "casting function pointer `{}` to `{}`, which truncates the value",
+                        from_snippet, cast_to
+                    ),
+                    "try",
+                    format!("{} as usize", from_snippet),
+                    applicability,
+                );
+            } else if cast_to.sty != ty::Uint(UintTy::Usize) {
+                span_lint_and_sugg(
+                    cx,
+                    FN_TO_NUMERIC_CAST,
+                    expr.span,
+                    &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+                    "try",
+                    format!("{} as usize", from_snippet),
+                    applicability,
+                );
+            }
+        },
+        _ => {},
+    }
+}
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for types used in structs, parameters and `let`
+    /// declarations above a certain complexity threshold.
+    ///
+    /// **Why is this bad?** Too complex types make the code less readable. Consider
+    /// using a `type` definition to simplify them.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct Foo {
+    ///     inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
+    /// }
+    /// ```
     pub TYPE_COMPLEXITY,
     complexity,
     "usage of very complex types that might be better factored into `type` definitions"
 }
 
-#[allow(missing_copy_implementations)]
-pub struct TypeComplexityPass {
+pub struct TypeComplexity {
     threshold: u64,
 }
 
-impl TypeComplexityPass {
+impl TypeComplexity {
     pub fn new(threshold: u64) -> Self {
-        Self {
-            threshold,
-        }
+        Self { threshold }
     }
 }
 
-impl LintPass for TypeComplexityPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(TYPE_COMPLEXITY)
-    }
-}
+impl_lint_pass!(TypeComplexity => [TYPE_COMPLEXITY]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexityPass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeComplexity {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -1131,12 +1316,12 @@ fn check_fn(
         decl: &'tcx FnDecl,
         _: &'tcx Body,
         _: Span,
-        _: NodeId,
+        _: HirId,
     ) {
         self.check_fndecl(cx, decl);
     }
 
-    fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx StructField) {
+    fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
         // enum variants are also struct fields now
         self.check_type(cx, &field.ty);
     }
@@ -1173,7 +1358,7 @@ fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
     }
 }
 
-impl<'a, 'tcx> TypeComplexityPass {
+impl<'a, 'tcx> TypeComplexity {
     fn check_fndecl(&self, cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl) {
         for arg in &decl.inputs {
             self.check_type(cx, arg);
@@ -1184,7 +1369,7 @@ fn check_fndecl(&self, cx: &LateContext<'a, 'tcx>, decl: &'tcx FnDecl) {
     }
 
     fn check_type(&self, cx: &LateContext<'_, '_>, ty: &hir::Ty) {
-        if in_macro(ty.span) {
+        if in_macro_or_desugar(ty.span) {
             return;
         }
         let score = {
@@ -1222,15 +1407,15 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
 
             // function types bring a lot of overhead
-            TyKind::BareFn(..) => (50 * self.nest, 1),
+            TyKind::BareFn(ref bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
 
             TyKind::TraitObject(ref param_bounds, _) => {
-                let has_lifetime_parameters = param_bounds
-                    .iter()
-                    .any(|bound| bound.bound_generic_params.iter().any(|gen| match gen.kind {
+                let has_lifetime_parameters = param_bounds.iter().any(|bound| {
+                    bound.bound_generic_params.iter().any(|gen| match gen.kind {
                         GenericParamKind::Lifetime { .. } => true,
                         _ => false,
-                    }));
+                    })
+                });
                 if has_lifetime_parameters {
                     // complex trait bounds like A<'a, 'b>
                     (50 * self.nest, 1)
@@ -1252,53 +1437,50 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-/// **What it does:** Checks for expressions where a character literal is cast
-/// to `u8` and suggests using a byte literal instead.
-///
-/// **Why is this bad?** In general, casting values to smaller types is
-/// error-prone and should be avoided where possible. In the particular case of
-/// converting a character literal to u8, it is easy to avoid by just using a
-/// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
-/// than `'a' as u8`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// 'x' as u8
-/// ```
-///
-/// A better version, using the byte literal:
-///
-/// ```rust
-/// b'x'
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for expressions where a character literal is cast
+    /// to `u8` and suggests using a byte literal instead.
+    ///
+    /// **Why is this bad?** In general, casting values to smaller types is
+    /// error-prone and should be avoided where possible. In the particular case of
+    /// converting a character literal to u8, it is easy to avoid by just using a
+    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
+    /// than `'a' as u8`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// 'x' as u8
+    /// ```
+    ///
+    /// A better version, using the byte literal:
+    ///
+    /// ```rust
+    /// b'x'
+    /// ```
     pub CHAR_LIT_AS_U8,
     complexity,
     "casting a character literal to u8"
 }
 
-pub struct CharLitAsU8;
-
-impl LintPass for CharLitAsU8 {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(CHAR_LIT_AS_U8)
-    }
-}
+declare_lint_pass!(CharLitAsU8 => [CHAR_LIT_AS_U8]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CharLitAsU8 {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        use syntax::ast::{LitKind, UintTy};
+        use syntax::ast::LitKind;
 
         if let ExprKind::Cast(ref e, _) = expr.node {
             if let ExprKind::Lit(ref l) = e.node {
                 if let LitKind::Char(_) = l.node {
-                    if ty::TyUint(UintTy::U8) == cx.tables.expr_ty(expr).sty && !in_macro(expr.span) {
+                    if ty::Uint(UintTy::U8) == cx.tables.expr_ty(expr).sty && !in_macro_or_desugar(expr.span) {
                         let msg = "casting character literal to u8. `char`s \
                                    are 4 bytes wide in rust, so casting to u8 \
                                    truncates them";
-                        let help = format!("Consider using a byte literal instead:\nb{}", snippet(cx, e.span, "'x'"));
+                        let help = format!(
+                            "Consider using a byte literal instead:\nb{}",
+                            snippet(cx, e.span, "'x'")
+                        );
                         span_help_and_lint(cx, CHAR_LIT_AS_U8, expr.span, msg, &help);
                     }
                 }
@@ -1307,40 +1489,36 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-/// **What it does:** Checks for comparisons where one side of the relation is
-/// either the minimum or maximum value for its type and warns if it involves a
-/// case that is always true or always false. Only integer and boolean types are
-/// checked.
-///
-/// **Why is this bad?** An expression like `min <= x` may misleadingly imply
-/// that is is possible for `x` to be less than the minimum. Expressions like
-/// `max < x` are probably mistakes.
-///
-/// **Known problems:** For `usize` the size of the current compile target will
-/// be assumed (e.g. 64 bits on 64 bit systems). This means code that uses such
-/// a comparison to detect target pointer width will trigger this lint. One can
-/// use `mem::sizeof` and compare its value or conditional compilation
-/// attributes
-/// like `#[cfg(target_pointer_width = "64")] ..` instead.
-///
-/// **Example:**
-/// ```rust
-/// vec.len() <= 0
-/// 100 > std::i32::MAX
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for comparisons where one side of the relation is
+    /// either the minimum or maximum value for its type and warns if it involves a
+    /// case that is always true or always false. Only integer and boolean types are
+    /// checked.
+    ///
+    /// **Why is this bad?** An expression like `min <= x` may misleadingly imply
+    /// that is is possible for `x` to be less than the minimum. Expressions like
+    /// `max < x` are probably mistakes.
+    ///
+    /// **Known problems:** For `usize` the size of the current compile target will
+    /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
+    /// a comparison to detect target pointer width will trigger this lint. One can
+    /// use `mem::sizeof` and compare its value or conditional compilation
+    /// attributes
+    /// like `#[cfg(target_pointer_width = "64")] ..` instead.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let vec: Vec<isize> = vec![];
+    /// if vec.len() <= 0 {}
+    /// if 100 > std::i32::MAX {}
+    /// ```
     pub ABSURD_EXTREME_COMPARISONS,
     correctness,
     "a comparison with a maximum or minimum value that is always true or false"
 }
 
-pub struct AbsurdExtremeComparisons;
-
-impl LintPass for AbsurdExtremeComparisons {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ABSURD_EXTREME_COMPARISONS)
-    }
-}
+declare_lint_pass!(AbsurdExtremeComparisons => [ABSURD_EXTREME_COMPARISONS]);
 
 enum ExtremeType {
     Minimum,
@@ -1358,17 +1536,12 @@ enum AbsurdComparisonResult {
     InequalityImpossible,
 }
 
-
-fn is_cast_between_fixed_and_target<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &'tcx Expr
-) -> bool {
-
+fn is_cast_between_fixed_and_target<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -> bool {
     if let ExprKind::Cast(ref cast_exp, _) = expr.node {
         let precast_ty = cx.tables.expr_ty(cast_exp);
         let cast_ty = cx.tables.expr_ty(expr);
 
-        return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty)
+        return is_isize_or_usize(precast_ty) != is_isize_or_usize(cast_ty);
     }
 
     false
@@ -1380,8 +1553,8 @@ fn detect_absurd_comparison<'a, 'tcx>(
     lhs: &'tcx Expr,
     rhs: &'tcx Expr,
 ) -> Option<(ExtremeExpr<'tcx>, AbsurdComparisonResult)> {
-    use crate::types::ExtremeType::*;
     use crate::types::AbsurdComparisonResult::*;
+    use crate::types::ExtremeType::*;
     use crate::utils::comparisons::*;
 
     // absurd comparison only makes sense on primitive types
@@ -1434,30 +1607,34 @@ fn detect_extreme_expr<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) -
     let cv = constant(cx, cx.tables, expr)?.0;
 
     let which = match (&ty.sty, cv) {
-        (&ty::TyBool, Constant::Bool(false)) |
-        (&ty::TyUint(_), Constant::Int(0)) => Minimum,
-        (&ty::TyInt(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::min_value() >> (128 - int_bits(cx.tcx, ity)), ity) => Minimum,
+        (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => Minimum,
+        (&ty::Int(ity), Constant::Int(i))
+            if i == unsext(cx.tcx, i128::min_value() >> (128 - int_bits(cx.tcx, ity)), ity) =>
+        {
+            Minimum
+        },
 
-        (&ty::TyBool, Constant::Bool(true)) => Maximum,
-        (&ty::TyInt(ity), Constant::Int(i)) if i == unsext(cx.tcx, i128::max_value() >> (128 - int_bits(cx.tcx, ity)), ity) => Maximum,
-        (&ty::TyUint(uty), Constant::Int(i)) if clip(cx.tcx, u128::max_value(), uty) == i => Maximum,
+        (&ty::Bool, Constant::Bool(true)) => Maximum,
+        (&ty::Int(ity), Constant::Int(i))
+            if i == unsext(cx.tcx, i128::max_value() >> (128 - int_bits(cx.tcx, ity)), ity) =>
+        {
+            Maximum
+        },
+        (&ty::Uint(uty), Constant::Int(i)) if clip(cx.tcx, u128::max_value(), uty) == i => Maximum,
 
         _ => return None,
     };
-    Some(ExtremeExpr {
-        which,
-        expr,
-    })
+    Some(ExtremeExpr { which, expr })
 }
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AbsurdExtremeComparisons {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        use crate::types::ExtremeType::*;
         use crate::types::AbsurdComparisonResult::*;
+        use crate::types::ExtremeType::*;
 
         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(expr.span) {
+                if !in_macro_or_desugar(expr.span) {
                     let msg = "this comparison involving the minimum or maximum element for this \
                                type contains a case that is always true or always false";
 
@@ -1489,34 +1666,28 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-/// **What it does:** Checks for comparisons where the relation is always either
-/// true or false, but where one side has been upcast so that the comparison is
-/// necessary. Only integer types are checked.
-///
-/// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
-/// will mistakenly imply that it is possible for `x` to be outside the range of
-/// `u8`.
-///
-/// **Known problems:**
-/// https://github.com/rust-lang-nursery/rust-clippy/issues/886
-///
-/// **Example:**
-/// ```rust
-/// let x : u8 = ...; (x as u32) > 300
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for comparisons where the relation is always either
+    /// true or false, but where one side has been upcast so that the comparison is
+    /// necessary. Only integer types are checked.
+    ///
+    /// **Why is this bad?** An expression like `let x : u8 = ...; (x as u32) > 300`
+    /// will mistakenly imply that it is possible for `x` to be outside the range of
+    /// `u8`.
+    ///
+    /// **Known problems:**
+    /// https://github.com/rust-lang/rust-clippy/issues/886
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x : u8 = ...; (x as u32) > 300
+    /// ```
     pub INVALID_UPCAST_COMPARISONS,
     pedantic,
     "a comparison involving an upcast which is always true or false"
 }
 
-pub struct InvalidUpcastComparisons;
-
-impl LintPass for InvalidUpcastComparisons {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(INVALID_UPCAST_COMPARISONS)
-    }
-}
+declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
 
 #[derive(Copy, Clone, Debug, Eq)]
 enum FullInt {
@@ -1525,7 +1696,7 @@ enum FullInt {
 }
 
 impl FullInt {
-    #[allow(cast_sign_loss)]
+    #[allow(clippy::cast_sign_loss)]
     fn cmp_s_u(s: i128, u: u128) -> Ordering {
         if s < 0 {
             Ordering::Less
@@ -1539,8 +1710,7 @@ fn cmp_s_u(s: i128, u: u128) -> Ordering {
 
 impl PartialEq for FullInt {
     fn eq(&self, other: &Self) -> bool {
-        self.partial_cmp(other)
-            .expect("partial_cmp only returns Some(_)") == Ordering::Equal
+        self.partial_cmp(other).expect("partial_cmp only returns Some(_)") == Ordering::Equal
     }
 }
 
@@ -1561,9 +1731,7 @@ fn cmp(&self, other: &Self) -> Ordering {
     }
 }
 
-
 fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<(FullInt, FullInt)> {
-    use syntax::ast::{IntTy, UintTy};
     use std::*;
 
     if let ExprKind::Cast(ref cast_exp, _) = expr.node {
@@ -1574,8 +1742,11 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) ->
             return None;
         }
         match pre_cast_ty.sty {
-            ty::TyInt(int_ty) => Some(match int_ty {
-                IntTy::I8 => (FullInt::S(i128::from(i8::min_value())), FullInt::S(i128::from(i8::max_value()))),
+            ty::Int(int_ty) => Some(match int_ty {
+                IntTy::I8 => (
+                    FullInt::S(i128::from(i8::min_value())),
+                    FullInt::S(i128::from(i8::max_value())),
+                ),
                 IntTy::I16 => (
                     FullInt::S(i128::from(i16::min_value())),
                     FullInt::S(i128::from(i16::max_value())),
@@ -1588,11 +1759,17 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) ->
                     FullInt::S(i128::from(i64::min_value())),
                     FullInt::S(i128::from(i64::max_value())),
                 ),
-                IntTy::I128 => (FullInt::S(i128::min_value() as i128), FullInt::S(i128::max_value() as i128)),
-                IntTy::Isize => (FullInt::S(isize::min_value() as i128), FullInt::S(isize::max_value() as i128)),
+                IntTy::I128 => (FullInt::S(i128::min_value()), FullInt::S(i128::max_value())),
+                IntTy::Isize => (
+                    FullInt::S(isize::min_value() as i128),
+                    FullInt::S(isize::max_value() as i128),
+                ),
             }),
-            ty::TyUint(uint_ty) => Some(match uint_ty {
-                UintTy::U8 => (FullInt::U(u128::from(u8::min_value())), FullInt::U(u128::from(u8::max_value()))),
+            ty::Uint(uint_ty) => Some(match uint_ty {
+                UintTy::U8 => (
+                    FullInt::U(u128::from(u8::min_value())),
+                    FullInt::U(u128::from(u8::max_value())),
+                ),
                 UintTy::U16 => (
                     FullInt::U(u128::from(u16::min_value())),
                     FullInt::U(u128::from(u16::max_value())),
@@ -1605,8 +1782,11 @@ fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) ->
                     FullInt::U(u128::from(u64::min_value())),
                     FullInt::U(u128::from(u64::max_value())),
                 ),
-                UintTy::U128 => (FullInt::U(u128::min_value() as u128), FullInt::U(u128::max_value() as u128)),
-                UintTy::Usize => (FullInt::U(usize::min_value() as u128), FullInt::U(usize::max_value() as u128)),
+                UintTy::U128 => (FullInt::U(u128::min_value()), FullInt::U(u128::max_value())),
+                UintTy::Usize => (
+                    FullInt::U(usize::min_value() as u128),
+                    FullInt::U(usize::max_value() as u128),
+                ),
             }),
             _ => None,
         }
@@ -1619,8 +1799,8 @@ fn node_as_const_fullint<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr)
     let val = constant(cx, cx.tables, expr)?.0;
     if let Constant::Int(const_int) = val {
         match cx.tables.expr_ty(expr).sty {
-            ty::TyInt(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
-            ty::TyUint(_) => Some(FullInt::U(const_int)),
+            ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+            ty::Uint(_) => Some(FullInt::U(const_int)),
             _ => None,
         }
     } else {
@@ -1661,29 +1841,37 @@ fn upcast_comparison_bounds_err<'a, 'tcx>(
                     err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
                 }
             } else if match rel {
-                Rel::Lt => if invert {
-                    norm_rhs_val < lb
-                } else {
-                    ub < norm_rhs_val
+                Rel::Lt => {
+                    if invert {
+                        norm_rhs_val < lb
+                    } else {
+                        ub < norm_rhs_val
+                    }
                 },
-                Rel::Le => if invert {
-                    norm_rhs_val <= lb
-                } else {
-                    ub <= norm_rhs_val
+                Rel::Le => {
+                    if invert {
+                        norm_rhs_val <= lb
+                    } else {
+                        ub <= norm_rhs_val
+                    }
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
                 err_upcast_comparison(cx, span, lhs, true)
             } else if match rel {
-                Rel::Lt => if invert {
-                    norm_rhs_val >= ub
-                } else {
-                    lb >= norm_rhs_val
+                Rel::Lt => {
+                    if invert {
+                        norm_rhs_val >= ub
+                    } else {
+                        lb >= norm_rhs_val
+                    }
                 },
-                Rel::Le => if invert {
-                    norm_rhs_val > ub
-                } else {
-                    lb > norm_rhs_val
+                Rel::Le => {
+                    if invert {
+                        norm_rhs_val > ub
+                    } else {
+                        lb > norm_rhs_val
+                    }
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
@@ -1712,39 +1900,36 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
     }
 }
 
-/// **What it does:** Checks for public `impl` or `fn` missing generalization
-/// over different hashers and implicitly defaulting to the default hashing
-/// algorithm (SipHash).
-///
-/// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
-/// used with them.
-///
-/// **Known problems:** Suggestions for replacing constructors can contain
-/// false-positives. Also applying suggestions can require modification of other
-/// pieces of code, possibly including external crates.
-///
-/// **Example:**
-/// ```rust
-/// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { ... }
-///
-/// pub foo(map: &mut HashMap<i32, i32>) { .. }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for public `impl` or `fn` missing generalization
+    /// over different hashers and implicitly defaulting to the default hashing
+    /// algorithm (SipHash).
+    ///
+    /// **Why is this bad?** `HashMap` or `HashSet` with custom hashers cannot be
+    /// used with them.
+    ///
+    /// **Known problems:** Suggestions for replacing constructors can contain
+    /// false-positives. Also applying suggestions can require modification of other
+    /// pieces of code, possibly including external crates.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use std::collections::HashMap;
+    /// # use std::hash::Hash;
+    /// # trait Serialize {};
+    /// impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
+    ///
+    /// pub fn foo(map: &mut HashMap<i32, i32>) { }
+    /// ```
     pub IMPLICIT_HASHER,
     style,
     "missing generalization over different hashers"
 }
 
-pub struct ImplicitHasher;
-
-impl LintPass for ImplicitHasher {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(IMPLICIT_HASHER)
-    }
-}
+declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitHasher {
-    #[allow(cast_possible_truncation)]
+    #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)]
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
         use syntax_pos::BytePos;
 
@@ -1794,7 +1979,7 @@ fn suggestion<'a, 'tcx>(
             }
         }
 
-        if !cx.access_levels.is_exported(item.id) {
+        if !cx.access_levels.is_exported(item.hir_id) {
             return;
         }
 
@@ -1810,13 +1995,16 @@ fn suggestion<'a, 'tcx>(
 
                     let generics_suggestion_span = generics.span.substitute_dummy({
                         let pos = snippet_opt(cx, item.span.until(target.span()))
-                            .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)))
-                            .expect("failed to create span for type arguments");
-                        Span::new(pos, pos, item.span.data().ctxt)
+                            .and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
+                        if let Some(pos) = pos {
+                            Span::new(pos, pos, item.span.data().ctxt)
+                        } else {
+                            return;
+                        }
                     });
 
                     let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
-                    for item in items.iter().map(|item| cx.tcx.hir.impl_item(item.id)) {
+                    for item in items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
                         ctr_vis.visit_impl_item(item);
                     }
 
@@ -1824,7 +2012,10 @@ fn suggestion<'a, 'tcx>(
                         cx,
                         IMPLICIT_HASHER,
                         target.span(),
-                        &format!("impl for `{}` should be generalized over different hashers", target.type_name()),
+                        &format!(
+                            "impl for `{}` should be generalized over different hashers",
+                            target.type_name()
+                        ),
                         move |db| {
                             suggestion(cx, db, generics.span, generics_suggestion_span, target, ctr_vis);
                         },
@@ -1832,7 +2023,7 @@ fn suggestion<'a, 'tcx>(
                 }
             },
             ItemKind::Fn(ref decl, .., ref generics, body_id) => {
-                let body = cx.tcx.hir.body(body_id);
+                let body = cx.tcx.hir().body(body_id);
 
                 for ty in &decl.inputs {
                     let mut vis = ImplicitHasherTypeVisitor::new(cx);
@@ -1881,24 +2072,36 @@ impl<'tcx> ImplicitHasherType<'tcx> {
     /// Checks that `ty` is a target type without a BuildHasher.
     fn new<'a>(cx: &LateContext<'a, 'tcx>, hir_ty: &hir::Ty) -> Option<Self> {
         if let TyKind::Path(QPath::Resolved(None, ref path)) = hir_ty.node {
-            let params: Vec<_> = path.segments.last().as_ref()?.args.as_ref()?
-                .args.iter().filter_map(|arg| match arg {
+            let params: Vec<_> = path
+                .segments
+                .last()
+                .as_ref()?
+                .args
+                .as_ref()?
+                .args
+                .iter()
+                .filter_map(|arg| match arg {
                     GenericArg::Type(ty) => Some(ty),
-                    GenericArg::Lifetime(_) => None,
-                }).collect();
+                    _ => None,
+                })
+                .collect();
             let params_len = params.len();
 
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
 
-            if match_path(path, &paths::HASHMAP) && params_len == 2 {
+            if match_path(path, &*paths::HASHMAP) && params_len == 2 {
                 Some(ImplicitHasherType::HashMap(
                     hir_ty.span,
                     ty,
                     snippet(cx, params[0].span, "K"),
                     snippet(cx, params[1].span, "V"),
                 ))
-            } else if match_path(path, &paths::HASHSET) && params_len == 1 {
-                Some(ImplicitHasherType::HashSet(hir_ty.span, ty, snippet(cx, params[0].span, "T")))
+            } else if match_path(path, &*paths::HASHSET) && params_len == 1 {
+                Some(ImplicitHasherType::HashSet(
+                    hir_ty.span,
+                    ty,
+                    snippet(cx, params[0].span, "T"),
+                ))
             } else {
                 None
             }
@@ -1980,8 +2183,10 @@ fn new(cx: &'a LateContext<'a, 'tcx>, target: &'b ImplicitHasherType<'tcx>) -> S
 
 impl<'a, 'b, 'tcx: 'a + 'b> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
     fn visit_body(&mut self, body: &'tcx Body) {
+        let prev_body = self.body;
         self.body = self.cx.tcx.body_tables(body.id());
         walk_body(self, body);
+        self.body = prev_body;
     }
 
     fn visit_expr(&mut self, e: &'tcx Expr) {
@@ -1994,11 +2199,11 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
                     return;
                 }
 
-                if match_path(ty_path, &paths::HASHMAP) {
-                    if method.ident.name == "new" {
+                if match_path(ty_path, &*paths::HASHMAP) {
+                    if method.ident.name == *sym::new {
                         self.suggestions
                             .insert(e.span, "HashMap::default()".to_string());
-                    } else if method.ident.name == "with_capacity" {
+                    } else if method.ident.name == *sym::with_capacity {
                         self.suggestions.insert(
                             e.span,
                             format!(
@@ -2007,11 +2212,11 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
                             ),
                         );
                     }
-                } else if match_path(ty_path, &paths::HASHSET) {
-                    if method.ident.name == "new" {
+                } else if match_path(ty_path, &*paths::HASHSET) {
+                    if method.ident.name == *sym::new {
                         self.suggestions
                             .insert(e.span, "HashSet::default()".to_string());
-                    } else if method.ident.name == "with_capacity" {
+                    } else if method.ident.name == *sym::with_capacity {
                         self.suggestions.insert(
                             e.span,
                             format!(
@@ -2028,6 +2233,63 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
     }
 
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
+        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
+    }
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
+    ///
+    /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
+    /// `UnsafeCell` is the only way to obtain aliasable data that is considered
+    /// mutable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// fn x(r: &i32) {
+    ///     unsafe {
+    ///         *(r as *const _ as *mut _) += 1;
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Instead consider using interior mutability types.
+    ///
+    /// ```rust
+    /// use std::cell::UnsafeCell;
+    ///
+    /// fn x(r: &UnsafeCell<i32>) {
+    ///     unsafe {
+    ///         *r.get() += 1;
+    ///     }
+    /// }
+    /// ```
+    pub CAST_REF_TO_MUT,
+    correctness,
+    "a cast of reference to a mutable pointer"
+}
+
+declare_lint_pass!(RefToMut => [CAST_REF_TO_MUT]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RefToMut {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if_chain! {
+            if let ExprKind::Unary(UnOp::UnDeref, e) = &expr.node;
+            if let ExprKind::Cast(e, t) = &e.node;
+            if let TyKind::Ptr(MutTy { mutbl: Mutability::MutMutable, .. }) = t.node;
+            if let ExprKind::Cast(e, t) = &e.node;
+            if let TyKind::Ptr(MutTy { mutbl: Mutability::MutImmutable, .. }) = t.node;
+            if let ty::Ref(..) = cx.tables.node_type(e.hir_id).sty;
+            then {
+                span_lint(
+                    cx,
+                    CAST_REF_TO_MUT,
+                    expr.span,
+                    "casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell",
+                );
+            }
+        }
     }
 }
index 0549e774fb55debb70f1c4b6b9408b591c9bf808..d96596bbb525b525213fbef487ad447c4176c414 100644 (file)
@@ -1,80 +1,70 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{is_allowed, snippet, span_help_and_lint};
 use rustc::hir::*;
-use syntax::ast::{LitKind, NodeId};
-use syntax::codemap::Span;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::ast::LitKind;
+use syntax::source_map::Span;
 use unicode_normalization::UnicodeNormalization;
-use crate::utils::{is_allowed, snippet, span_help_and_lint};
 
-/// **What it does:** Checks for the Unicode zero-width space in the code.
-///
-/// **Why is this bad?** Having an invisible character in the code makes for all
-/// sorts of April fools, but otherwise is very much frowned upon.
-///
-/// **Known problems:** None.
-///
-/// **Example:** You don't see it, but there may be a zero-width space
-/// somewhere in this text.
 declare_clippy_lint! {
+    /// **What it does:** Checks for the Unicode zero-width space in the code.
+    ///
+    /// **Why is this bad?** Having an invisible character in the code makes for all
+    /// sorts of April fools, but otherwise is very much frowned upon.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:** You don't see it, but there may be a zero-width space
+    /// somewhere in this text.
     pub ZERO_WIDTH_SPACE,
     correctness,
     "using a zero-width space in a string literal, which is confusing"
 }
 
-/// **What it does:** Checks for non-ASCII characters in string literals.
-///
-/// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset
-/// back. Even so, there still are editors and other programs out there that
-/// don't work well with Unicode. So if the code is meant to be used
-/// internationally, on multiple operating systems, or has other portability
-/// requirements, activating this lint could be useful.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = "Hä?"
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for non-ASCII characters in string literals.
+    ///
+    /// **Why is this bad?** Yeah, we know, the 90's called and wanted their charset
+    /// back. Even so, there still are editors and other programs out there that
+    /// don't work well with Unicode. So if the code is meant to be used
+    /// internationally, on multiple operating systems, or has other portability
+    /// requirements, activating this lint could be useful.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = "Hä?"
+    /// ```
     pub NON_ASCII_LITERAL,
     pedantic,
-    "using any literal non-ASCII chars in a string literal instead of \
-     using the `\\u` escape"
+    "using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
 }
 
-/// **What it does:** Checks for string literals that contain Unicode in a form
-/// that is not equal to its
-/// [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms).
-///
-/// **Why is this bad?** If such a string is compared to another, the results
-/// may be surprising.
-///
-/// **Known problems** None.
-///
-/// **Example:** You may not see it, but “à” and “à” aren't the same string. The
-/// former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`.
 declare_clippy_lint! {
+    /// **What it does:** Checks for string literals that contain Unicode in a form
+    /// that is not equal to its
+    /// [NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms).
+    ///
+    /// **Why is this bad?** If such a string is compared to another, the results
+    /// may be surprising.
+    ///
+    /// **Known problems** None.
+    ///
+    /// **Example:** You may not see it, but “à” and “à” aren't the same string. The
+    /// former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`.
     pub UNICODE_NOT_NFC,
     pedantic,
-    "using a unicode literal not in NFC normal form (see \
-     [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
+    "using a unicode literal not in NFC normal form (see [unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
 }
 
-
-#[derive(Copy, Clone)]
-pub struct Unicode;
-
-impl LintPass for Unicode {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC)
-    }
-}
+declare_lint_pass!(Unicode => [ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if let ExprKind::Lit(ref lit) = expr.node {
             if let LitKind::Str(_, _) = lit.node {
-                check_str(cx, lit.span, expr.id)
+                check_str(cx, lit.span, expr.hir_id)
             }
         }
     }
@@ -94,7 +84,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
     result
 }
 
-fn check_str(cx: &LateContext<'_, '_>, span: Span, id: NodeId) {
+fn check_str(cx: &LateContext<'_, '_>, span: Span, id: HirId) {
     let string = snippet(cx, span, "");
     if string.contains('\u{200B}') {
         span_help_and_lint(
@@ -130,7 +120,10 @@ fn check_str(cx: &LateContext<'_, '_>, span: Span, id: NodeId) {
             UNICODE_NOT_NFC,
             span,
             "non-nfc unicode sequence detected",
-            &format!("Consider replacing the string with:\n\"{}\"", string.nfc().collect::<String>()),
+            &format!(
+                "Consider replacing the string with:\n\"{}\"",
+                string.nfc().collect::<String>()
+            ),
         );
     }
 }
index 2f8b3ab836db99ab2c6348d1675b1f922cd358e6..deeeefb88ab5770671eeb0e57ade8c0d1f915e25 100644 (file)
@@ -1,38 +1,32 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::span_lint;
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::*;
-use syntax::codemap::Span;
+use syntax::source_map::Span;
 use syntax::symbol::LocalInternedString;
-use crate::utils::span_lint;
 
-/// **What it does:** Checks for imports that remove "unsafe" from an item's
-/// name.
-///
-/// **Why is this bad?** Renaming makes it less clear which traits and
-/// structures are unsafe.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// use std::cell::{UnsafeCell as TotallySafeCell};
-///
-/// extern crate crossbeam;
-/// use crossbeam::{spawn_unsafe as spawn};
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for imports that remove "unsafe" from an item's
+    /// name.
+    ///
+    /// **Why is this bad?** Renaming makes it less clear which traits and
+    /// structures are unsafe.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// use std::cell::{UnsafeCell as TotallySafeCell};
+    ///
+    /// extern crate crossbeam;
+    /// use crossbeam::{spawn_unsafe as spawn};
+    /// ```
     pub UNSAFE_REMOVED_FROM_NAME,
     style,
     "`unsafe` removed from API names on import"
 }
 
-pub struct UnsafeNameRemoval;
-
-impl LintPass for UnsafeNameRemoval {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNSAFE_REMOVED_FROM_NAME)
-    }
-}
+declare_lint_pass!(UnsafeNameRemoval => [UNSAFE_REMOVED_FROM_NAME]);
 
 impl EarlyLintPass for UnsafeNameRemoval {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
@@ -52,14 +46,13 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) {
                 .expect("use paths cannot be empty")
                 .ident;
             unsafe_to_safe_check(old_name, new_name, cx, span);
-        }
-        UseTreeKind::Simple(None, ..) |
-        UseTreeKind::Glob => {},
+        },
+        UseTreeKind::Simple(None, ..) | UseTreeKind::Glob => {},
         UseTreeKind::Nested(ref nested_use_tree) => {
             for &(ref use_tree, _) in nested_use_tree {
                 check_use_tree(use_tree, cx, span);
             }
-        }
+        },
     }
 }
 
@@ -71,7 +64,10 @@ fn unsafe_to_safe_check(old_name: Ident, new_name: Ident, cx: &EarlyContext<'_>,
             cx,
             UNSAFE_REMOVED_FROM_NAME,
             span,
-            &format!("removed \"unsafe\" from the name of `{}` in use as `{}`", old_str, new_str),
+            &format!(
+                "removed \"unsafe\" from the name of `{}` in use as `{}`",
+                old_str, new_str
+            ),
         );
     }
 }
index a9a7e102ab274bf62554142bd40468c8f3c80926..b807a62efccd576251ee3c0737dd78848a502123 100644 (file)
@@ -1,47 +1,41 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir;
 use crate::utils::{is_try, match_qpath, match_trait_method, paths, span_lint};
+use rustc::hir;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for unused written/read amount.
-///
-/// **Why is this bad?** `io::Write::write` and `io::Read::read` are not
-/// guaranteed to
-/// process the entire buffer. They return how many bytes were processed, which
-/// might be smaller
-/// than a given buffer's length. If you don't need to deal with
-/// partial-write/read, use
-/// `write_all`/`read_exact` instead.
-///
-/// **Known problems:** Detects only common patterns.
-///
-/// **Example:**
-/// ```rust,ignore
-/// use std::io;
-/// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
-///     // must be `w.write_all(b"foo")?;`
-///     w.write(b"foo")?;
-///     Ok(())
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for unused written/read amount.
+    ///
+    /// **Why is this bad?** `io::Write::write` and `io::Read::read` are not
+    /// guaranteed to
+    /// process the entire buffer. They return how many bytes were processed, which
+    /// might be smaller
+    /// than a given buffer's length. If you don't need to deal with
+    /// partial-write/read, use
+    /// `write_all`/`read_exact` instead.
+    ///
+    /// **Known problems:** Detects only common patterns.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// use std::io;
+    /// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
+    ///     // must be `w.write_all(b"foo")?;`
+    ///     w.write(b"foo")?;
+    ///     Ok(())
+    /// }
+    /// ```
     pub UNUSED_IO_AMOUNT,
     correctness,
     "unused written/read amount"
 }
 
-pub struct UnusedIoAmount;
-
-impl LintPass for UnusedIoAmount {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNUSED_IO_AMOUNT)
-    }
-}
+declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedIoAmount {
     fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) {
         let expr = match s.node {
-            hir::StmtKind::Semi(ref expr, _) | hir::StmtKind::Expr(ref expr, _) => &**expr,
+            hir::StmtKind::Semi(ref expr) | hir::StmtKind::Expr(ref expr) => &**expr,
             _ => return,
         };
 
@@ -49,7 +43,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) {
             hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => {
                 if let hir::ExprKind::Call(ref func, ref args) = res.node {
                     if let hir::ExprKind::Path(ref path) = func.node {
-                        if match_qpath(path, &paths::TRY_INTO_RESULT) && args.len() == 1 {
+                        if match_qpath(path, &*paths::TRY_INTO_RESULT) && args.len() == 1 {
                             check_method_call(cx, &args[0], expr);
                         }
                     }
@@ -73,14 +67,14 @@ fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) {
 fn check_method_call(cx: &LateContext<'_, '_>, call: &hir::Expr, expr: &hir::Expr) {
     if let hir::ExprKind::MethodCall(ref path, _, _) = call.node {
         let symbol = &*path.ident.as_str();
-        if match_trait_method(cx, call, &paths::IO_READ) && symbol == "read" {
+        if match_trait_method(cx, call, &*paths::IO_READ) && symbol == "read" {
             span_lint(
                 cx,
                 UNUSED_IO_AMOUNT,
                 expr.span,
                 "handle read amount returned or use `Read::read_exact` instead",
             );
-        } else if match_trait_method(cx, call, &paths::IO_WRITE) && symbol == "write" {
+        } else if match_trait_method(cx, call, &*paths::IO_WRITE) && symbol == "write" {
             span_lint(
                 cx,
                 UNUSED_IO_AMOUNT,
index 1681a303fd37b9fd38bf53708e4ea5560e6c1bf5..4b41a02de974b276b9c110144fd2b621f813d091 100644 (file)
@@ -1,45 +1,38 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{in_macro_or_desugar, span_lint};
 use rustc::hir;
 use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
-use std::collections::HashMap;
-use syntax::ast;
-use syntax::codemap::Span;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::FxHashMap;
+use syntax::source_map::Span;
 use syntax::symbol::LocalInternedString;
-use crate::utils::{in_macro, span_lint};
 
-/// **What it does:** Checks for unused labels.
-///
-/// **Why is this bad?** Maybe the label should be used in which case there is
-/// an error in the code or it should be removed.
-///
-/// **Known problems:** Hopefully none.
-///
-/// **Example:**
-/// ```rust,ignore
-/// fn unused_label() {
-///     'label: for i in 1..2 {
-///         if i > 4 { continue }
-///     }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for unused labels.
+    ///
+    /// **Why is this bad?** Maybe the label should be used in which case there is
+    /// an error in the code or it should be removed.
+    ///
+    /// **Known problems:** Hopefully none.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// fn unused_label() {
+    ///     'label: for i in 1..2 {
+    ///         if i > 4 { continue }
+    ///     }
+    /// ```
     pub UNUSED_LABEL,
     complexity,
     "unused labels"
 }
 
-pub struct UnusedLabel;
-
 struct UnusedLabelVisitor<'a, 'tcx: 'a> {
-    labels: HashMap<LocalInternedString, Span>,
+    labels: FxHashMap<LocalInternedString, Span>,
     cx: &'a LateContext<'a, 'tcx>,
 }
 
-impl LintPass for UnusedLabel {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(UNUSED_LABEL)
-    }
-}
+declare_lint_pass!(UnusedLabel => [UNUSED_LABEL]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel {
     fn check_fn(
@@ -49,15 +42,15 @@ fn check_fn(
         decl: &'tcx hir::FnDecl,
         body: &'tcx hir::Body,
         span: Span,
-        fn_id: ast::NodeId,
+        fn_id: hir::HirId,
     ) {
-        if in_macro(span) {
+        if in_macro_or_desugar(span) {
             return;
         }
 
         let mut v = UnusedLabelVisitor {
             cx,
-            labels: HashMap::new(),
+            labels: FxHashMap::default(),
         };
         walk_fn(&mut v, kind, decl, body.id(), span, fn_id);
 
@@ -70,8 +63,10 @@ fn check_fn(
 impl<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
-            hir::ExprKind::Break(destination, _) | hir::ExprKind::Continue(destination) => if let Some(label) = destination.label {
-                self.labels.remove(&label.ident.as_str());
+            hir::ExprKind::Break(destination, _) | hir::ExprKind::Continue(destination) => {
+                if let Some(label) = destination.label {
+                    self.labels.remove(&label.ident.as_str());
+                }
             },
             hir::ExprKind::Loop(_, Some(label), _) | hir::ExprKind::While(_, _, Some(label)) => {
                 self.labels.insert(label.ident.as_str(), expr.span);
@@ -82,6 +77,6 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         walk_expr(self, expr);
     }
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::All(&self.cx.tcx.hir)
+        NestedVisitorMap::All(&self.cx.tcx.hir())
     }
 }
index 6cafcaeffe9749995d046bec79ffaebca4bcc2c5..9949a086f93aa1cc2a70641afbfdf86752c05cff 100644 (file)
@@ -1,62 +1,62 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
 use if_chain::if_chain;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-use crate::utils::{in_macro, match_type, paths, span_lint_and_then, usage::is_potentially_mutated};
+use crate::utils::sym;
+use crate::utils::{
+    higher::if_block, in_macro_or_desugar, match_type, paths, span_lint_and_then, usage::is_potentially_mutated,
+};
 use rustc::hir::intravisit::*;
 use rustc::hir::*;
-use syntax::ast::NodeId;
-use syntax::codemap::Span;
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail.
-///
-/// **Why is this bad?** Using `if let` or `match` is more idiomatic.
-///
-/// **Known problems:** Limitations of the borrow checker might make unwrap() necessary sometimes?
-///
-/// **Example:**
-/// ```rust
-/// if option.is_some() {
-///     do_something_with(option.unwrap())
-/// }
-/// ```
-///
-/// Could be written:
-///
-/// ```rust
-/// if let Some(value) = option {
-///     do_something_with(value)
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail.
+    ///
+    /// **Why is this bad?** Using `if let` or `match` is more idiomatic.
+    ///
+    /// **Known problems:** Limitations of the borrow checker might make unwrap() necessary sometimes?
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if option.is_some() {
+    ///     do_something_with(option.unwrap())
+    /// }
+    /// ```
+    ///
+    /// Could be written:
+    ///
+    /// ```rust
+    /// if let Some(value) = option {
+    ///     do_something_with(value)
+    /// }
+    /// ```
     pub UNNECESSARY_UNWRAP,
     nursery,
     "checks for calls of unwrap[_err]() that cannot fail"
 }
 
-/// **What it does:** Checks for calls of `unwrap[_err]()` that will always fail.
-///
-/// **Why is this bad?** If panicking is desired, an explicit `panic!()` should be used.
-///
-/// **Known problems:** This lint only checks `if` conditions not assignments.
-/// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
-///
-/// **Example:**
-/// ```rust
-/// if option.is_none() {
-///     do_something_with(option.unwrap())
-/// }
-/// ```
-///
-/// This code will always panic. The if condition should probably be inverted.
 declare_clippy_lint! {
+    /// **What it does:** Checks for calls of `unwrap[_err]()` that will always fail.
+    ///
+    /// **Why is this bad?** If panicking is desired, an explicit `panic!()` should be used.
+    ///
+    /// **Known problems:** This lint only checks `if` conditions not assignments.
+    /// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// if option.is_none() {
+    ///     do_something_with(option.unwrap())
+    /// }
+    /// ```
+    ///
+    /// This code will always panic. The if condition should probably be inverted.
     pub PANICKING_UNWRAP,
     nursery,
     "checks for calls of unwrap[_err]() that will always fail"
 }
 
-pub struct Pass;
-
 /// Visitor that keeps track of which variables are unwrappable.
 struct UnwrappableVariablesVisitor<'a, 'tcx: 'a> {
     unwrappables: Vec<UnwrapInfo<'tcx>>,
@@ -96,7 +96,7 @@ fn collect_unwrap_info<'a, 'tcx: 'a>(
             if let ExprKind::MethodCall(method_name, _, args) = &expr.node;
             if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].node;
             let ty = cx.tables.expr_ty(&args[0]);
-            if match_type(cx, ty, &paths::OPTION) || match_type(cx, ty, &paths::RESULT);
+            if match_type(cx, ty, &*paths::OPTION) || match_type(cx, ty, &*paths::RESULT);
             let name = method_name.ident.as_str();
             if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name);
             then {
@@ -133,7 +133,7 @@ fn visit_branch(&mut self, cond: &'tcx Expr, branch: &'tcx Expr, else_branch: bo
 
 impl<'a, 'tcx: 'a> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr) {
-        if let ExprKind::If(cond, then, els) = &expr.node {
+        if let Some((cond, then, els)) = if_block(&expr) {
             walk_expr(self, cond);
             self.visit_branch(cond, then, false);
             if let Some(els) = els {
@@ -144,10 +144,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
             if_chain! {
                 if let ExprKind::MethodCall(ref method_name, _, ref args) = expr.node;
                 if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].node;
-                if ["unwrap", "unwrap_err"].contains(&&*method_name.ident.as_str());
-                let call_to_unwrap = method_name.ident.name == "unwrap";
+                if [*sym::unwrap, *sym::unwrap_err].contains(&method_name.ident.name);
+                let call_to_unwrap = method_name.ident.name == *sym::unwrap;
                 if let Some(unwrappable) = self.unwrappables.iter()
-                    .find(|u| u.ident.def == path.def);
+                    .find(|u| u.ident.res == path.res);
                 then {
                     if call_to_unwrap == unwrappable.safe_to_unwrap {
                         span_lint_and_then(
@@ -176,17 +176,13 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
     }
 
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
+        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
     }
 }
 
-impl<'a> LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(PANICKING_UNWRAP, UNNECESSARY_UNWRAP)
-    }
-}
+declare_lint_pass!(Unwrap => [PANICKING_UNWRAP, UNNECESSARY_UNWRAP]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Unwrap {
     fn check_fn(
         &mut self,
         cx: &LateContext<'a, 'tcx>,
@@ -194,9 +190,9 @@ fn check_fn(
         decl: &'tcx FnDecl,
         body: &'tcx Body,
         span: Span,
-        fn_id: NodeId,
+        fn_id: HirId,
     ) {
-        if in_macro(span) {
+        if in_macro_or_desugar(span) {
             return;
         }
 
index 79da4c7d288d51afba0f642afa3a6c07a0f63dfb..1a0a3474d88b274b34a4ebbc7d6f50a75f04231b 100644 (file)
-use crate::utils::{in_macro, span_lint_and_sugg};
 use if_chain::if_chain;
-use rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor};
+use rustc::hir;
+use rustc::hir::def::{CtorKind, DefKind, Res};
+use rustc::hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
 use rustc::hir::*;
-use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
 use rustc::ty;
-use rustc::{declare_lint, lint_array};
-use syntax::ast::NodeId;
-use syntax_pos::symbol::keywords::SelfType;
-
-/// **What it does:** Checks for unnecessary repetition of structure name when a
-/// replacement with `Self` is applicable.
-///
-/// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
-/// name
-/// feels inconsistent.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// struct Foo {}
-/// impl Foo {
-///     fn new() -> Foo {
-///         Foo {}
-///     }
-/// }
-/// ```
-/// could be
-/// ```
-/// struct Foo {}
-/// impl Foo {
-///     fn new() -> Self {
-///         Self {}
-///     }
-/// }
-/// ```
+use rustc::ty::{DefIdTree, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax_pos::symbol::keywords::SelfUpper;
+
+use crate::utils::span_lint_and_sugg;
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for unnecessary repetition of structure name when a
+    /// replacement with `Self` is applicable.
+    ///
+    /// **Why is this bad?** Unnecessary repetition. Mixed use of `Self` and struct
+    /// name
+    /// feels inconsistent.
+    ///
+    /// **Known problems:**
+    /// - False positive when using associated types (#2843)
+    /// - False positives in some situations when using generics (#3410)
+    ///
+    /// **Example:**
+    /// ```rust
+    /// struct Foo {}
+    /// impl Foo {
+    ///     fn new() -> Foo {
+    ///         Foo {}
+    ///     }
+    /// }
+    /// ```
+    /// could be
+    /// ```rust
+    /// struct Foo {}
+    /// impl Foo {
+    ///     fn new() -> Self {
+    ///         Self {}
+    ///     }
+    /// }
+    /// ```
     pub USE_SELF,
     pedantic,
     "Unnecessary structure name repetition whereas `Self` is applicable"
 }
 
-#[derive(Copy, Clone, Default)]
-pub struct UseSelf;
-
-impl LintPass for UseSelf {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(USE_SELF)
-    }
-}
+declare_lint_pass!(UseSelf => [USE_SELF]);
 
 const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
 
 fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
+    // Path segments only include actual path, no methods or fields.
+    let last_path_span = path.segments.last().expect(SEGMENTS_MSG).ident.span;
+    // Only take path up to the end of last_path_span.
+    let span = path.span.with_hi(last_path_span.hi());
+
     span_lint_and_sugg(
         cx,
         USE_SELF,
-        path.span,
+        span,
         "unnecessary structure name repetition",
         "use the applicable keyword",
         "Self".to_owned(),
+        Applicability::MachineApplicable,
     );
 }
 
 struct TraitImplTyVisitor<'a, 'tcx: 'a> {
-    item_path: &'a Path,
+    item_type: Ty<'tcx>,
     cx: &'a LateContext<'a, 'tcx>,
     trait_type_walker: ty::walk::TypeWalker<'tcx>,
     impl_type_walker: ty::walk::TypeWalker<'tcx>,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TraitImplTyVisitor<'a, 'tcx> {
-    fn visit_ty(&mut self, t: &'tcx Ty) {
+    fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         let trait_ty = self.trait_type_walker.next();
         let impl_ty = self.impl_type_walker.next();
 
         if let TyKind::Path(QPath::Resolved(_, path)) = &t.node {
-            if self.item_path.def == path.def {
-                let is_self_ty = if let def::Def::SelfTy(..) = path.def {
-                    true
-                } else {
-                    false
-                };
-
-                if !is_self_ty && impl_ty != trait_ty {
-                    // The implementation and trait types don't match which means that
-                    // the concrete type was specified by the implementation but
-                    // it didn't use `Self`
-                    span_use_self_lint(self.cx, path);
+            // The implementation and trait types don't match which means that
+            // the concrete type was specified by the implementation
+            if impl_ty != trait_ty {
+                if let Some(impl_ty) = impl_ty {
+                    if self.item_type == impl_ty {
+                        let is_self_ty = if let def::Res::SelfTy(..) = path.res {
+                            true
+                        } else {
+                            false
+                        };
+
+                        if !is_self_ty {
+                            span_use_self_lint(self.cx, path);
+                        }
+                    }
                 }
             }
         }
+
         walk_ty(self, t)
     }
 
@@ -101,7 +110,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
 fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
     cx: &'a LateContext<'a, 'tcx>,
-    item_path: &'a Path,
+    item_type: Ty<'tcx>,
     impl_item: &ImplItem,
     impl_decl: &'tcx FnDecl,
     impl_trait_ref: &ty::TraitRef<'_>,
@@ -120,7 +129,7 @@ fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
     let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
     let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig);
 
-    let impl_method_def_id = cx.tcx.hir.local_def_id(impl_item.id);
+    let impl_method_def_id = cx.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
     let impl_method_sig = cx.tcx.fn_sig(impl_method_def_id);
     let impl_method_sig = cx.tcx.erase_late_bound_regions(&impl_method_sig);
 
@@ -132,7 +141,7 @@ fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
 
     // `impl_decl_ty` (of type `hir::Ty`) represents the type declared in the signature.
     // `impl_ty` (of type `ty:TyS`) is the concrete type that the compiler has determined for
-    // that declaration.  We use `impl_decl_ty` to see if the type was declared as `Self`
+    // that declaration. We use `impl_decl_ty` to see if the type was declared as `Self`
     // and use `impl_ty` to check its concrete type.
     for (impl_decl_ty, (impl_ty, trait_ty)) in impl_decl.inputs.iter().chain(output_ty).zip(
         impl_method_sig
@@ -142,7 +151,7 @@ fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
     ) {
         let mut visitor = TraitImplTyVisitor {
             cx,
-            item_path,
+            item_type,
             trait_type_walker: trait_ty.walk(),
             impl_type_walker: impl_ty.walk(),
         };
@@ -153,7 +162,7 @@ fn check_trait_method_impl_decl<'a, 'tcx: 'a>(
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
-        if in_macro(item.span) {
+        if in_external_macro(cx.sess(), item.span) {
             return;
         }
         if_chain! {
@@ -164,7 +173,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
                 let should_check = if let Some(ref params) = *parameters {
                     !params.parenthesized && !params.args.iter().any(|arg| match arg {
                         GenericArg::Lifetime(_) => true,
-                        GenericArg::Type(_) => false,
+                        _ => false,
                     })
                 } else {
                     true
@@ -175,16 +184,18 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
                         item_path,
                         cx,
                     };
-                    let impl_def_id = cx.tcx.hir.local_def_id(item.id);
+                    let impl_def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
                     let impl_trait_ref = cx.tcx.impl_trait_ref(impl_def_id);
 
                     if let Some(impl_trait_ref) = impl_trait_ref {
                         for impl_item_ref in refs {
-                            let impl_item = cx.tcx.hir.impl_item(impl_item_ref.id);
+                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                             if let ImplItemKind::Method(MethodSig{ decl: impl_decl, .. }, impl_body_id)
                                     = &impl_item.node {
-                                check_trait_method_impl_decl(cx, item_path, impl_item, impl_decl, &impl_trait_ref);
-                                let body = cx.tcx.hir.body(*impl_body_id);
+                                let item_type = cx.tcx.type_of(impl_def_id);
+                                check_trait_method_impl_decl(cx, item_type, impl_item, impl_decl, &impl_trait_ref);
+
+                                let body = cx.tcx.hir().body(*impl_body_id);
                                 visitor.visit_body(body);
                             } else {
                                 visitor.visit_impl_item(impl_item);
@@ -192,7 +203,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
                         }
                     } else {
                         for impl_item_ref in refs {
-                            let impl_item = cx.tcx.hir.impl_item(impl_item_ref.id);
+                            let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
                             visitor.visit_impl_item(impl_item);
                         }
                     }
@@ -208,15 +219,35 @@ struct UseSelfVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
-    fn visit_path(&mut self, path: &'tcx Path, _id: NodeId) {
-        if self.item_path.def == path.def && path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfType.name() {
-            span_use_self_lint(self.cx, path);
+    fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
+        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
+            if self.item_path.res == path.res {
+                span_use_self_lint(self.cx, path);
+            } else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, CtorKind::Fn), ctor_did) = path.res {
+                if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_did) {
+                    span_use_self_lint(self.cx, path);
+                }
+            }
         }
-
         walk_path(self, path);
     }
 
+    fn visit_item(&mut self, item: &'tcx Item) {
+        match item.node {
+            ItemKind::Use(..)
+            | ItemKind::Static(..)
+            | ItemKind::Enum(..)
+            | ItemKind::Struct(..)
+            | ItemKind::Union(..)
+            | ItemKind::Impl(..)
+            | ItemKind::Fn(..) => {
+                // Don't check statements that shadow `Self` or where `Self` can't be used
+            },
+            _ => walk_item(self, item),
+        }
+    }
+
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir)
+        NestedVisitorMap::All(&self.cx.tcx.hir())
     }
 }
diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs
new file mode 100644 (file)
index 0000000..bec8d53
--- /dev/null
@@ -0,0 +1,115 @@
+use rustc::session::Session;
+use rustc_errors::Applicability;
+use std::str::FromStr;
+use syntax::ast;
+
+/// Deprecation status of attributes known by Clippy.
+#[allow(dead_code)]
+pub enum DeprecationStatus {
+    /// Attribute is deprecated
+    Deprecated,
+    /// Attribute is deprecated and was replaced by the named attribute
+    Replaced(&'static str),
+    None,
+}
+
+pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
+    ("author", DeprecationStatus::None),
+    ("cognitive_complexity", DeprecationStatus::None),
+    (
+        "cyclomatic_complexity",
+        DeprecationStatus::Replaced("cognitive_complexity"),
+    ),
+    ("dump", DeprecationStatus::None),
+];
+
+pub struct LimitStack {
+    stack: Vec<u64>,
+}
+
+impl Drop for LimitStack {
+    fn drop(&mut self) {
+        assert_eq!(self.stack.len(), 1);
+    }
+}
+
+impl LimitStack {
+    pub fn new(limit: u64) -> Self {
+        Self { stack: vec![limit] }
+    }
+    pub fn limit(&self) -> u64 {
+        *self.stack.last().expect("there should always be a value in the stack")
+    }
+    pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
+        let stack = &mut self.stack;
+        parse_attrs(sess, attrs, name, |val| stack.push(val));
+    }
+    pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
+        let stack = &mut self.stack;
+        parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
+    }
+}
+
+pub fn get_attr<'a>(
+    sess: &'a Session,
+    attrs: &'a [ast::Attribute],
+    name: &'static str,
+) -> impl Iterator<Item = &'a ast::Attribute> {
+    attrs.iter().filter(move |attr| {
+        let attr_segments = &attr.path.segments;
+        if attr_segments.len() == 2 && attr_segments[0].ident.to_string() == "clippy" {
+            if let Some(deprecation_status) =
+                BUILTIN_ATTRIBUTES
+                    .iter()
+                    .find_map(|(builtin_name, deprecation_status)| {
+                        if *builtin_name == attr_segments[1].ident.to_string() {
+                            Some(deprecation_status)
+                        } else {
+                            None
+                        }
+                    })
+            {
+                let mut db = sess.struct_span_err(attr_segments[1].ident.span, "Usage of deprecated attribute");
+                match deprecation_status {
+                    DeprecationStatus::Deprecated => {
+                        db.emit();
+                        false
+                    },
+                    DeprecationStatus::Replaced(new_name) => {
+                        db.span_suggestion(
+                            attr_segments[1].ident.span,
+                            "consider using",
+                            new_name.to_string(),
+                            Applicability::MachineApplicable,
+                        );
+                        db.emit();
+                        false
+                    },
+                    DeprecationStatus::None => {
+                        db.cancel();
+                        attr_segments[1].ident.to_string() == name
+                    },
+                }
+            } else {
+                sess.span_err(attr_segments[1].ident.span, "Usage of unknown attribute");
+                false
+            }
+        } else {
+            false
+        }
+    })
+}
+
+fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) {
+    for attr in get_attr(sess, attrs, name) {
+        if let Some(ref value) = attr.value_str() {
+            if let Ok(value) = FromStr::from_str(&value.as_str()) {
+                f(value)
+            } else {
+                sess.span_err(attr.span, "not a number");
+            }
+        } else {
+            sess.span_err(attr.span, "bad clippy attribute");
+        }
+    }
+}
index 4310325475a3e49ca643b5b5a1083a9920712816..5b88494ae7b7186685e1572fd4902ca702582cbc 100644 (file)
@@ -1,61 +1,54 @@
 //! A group of attributes that can be attached to Rust code in order
 //! to generate a clippy lint detecting said code automatically.
 
-#![allow(print_stdout, use_debug)]
-
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{get_attr, higher};
 use rustc::hir;
-use rustc::hir::{Expr, ExprKind, QPath, TyKind, Pat, PatKind, BindingAnnotation, StmtKind, DeclKind, Stmt};
 use rustc::hir::intravisit::{NestedVisitorMap, Visitor};
-use syntax::ast::{Attribute, LitKind, DUMMY_NODE_ID};
-use std::collections::HashMap;
-use crate::utils::get_attr;
+use rustc::hir::{BindingAnnotation, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::session::Session;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_data_structures::fx::FxHashMap;
+use syntax::ast::{Attribute, LitKind};
 
-/// **What it does:** Generates clippy code that detects the offending pattern
-///
-/// **Example:**
-/// ```rust
-/// // ./tests/ui/my_lint.rs
-/// fn foo() {
-///     // detect the following pattern
-///     #[clippy::author]
-///     if x == 42 {
-///         // but ignore everything from here on
-///         #![clippy::author = "ignore"]
-///     }
-/// }
-/// ```
-///
-/// Running `TESTNAME=ui/my_lint cargo test --test compile-test` will produce
-/// a `./tests/ui/new_lint.stdout` file with the generated code:
-///
-/// ```rust
-/// // ./tests/ui/new_lint.stdout
-/// if_chain!{
-///     if let ExprKind::If(ref cond, ref then, None) = item.node,
-///     if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.node,
-///     if let ExprKind::Path(ref path) = left.node,
-///     if let ExprKind::Lit(ref lit) = right.node,
-///     if let LitKind::Int(42, _) = lit.node,
-///     then {
-///         // report your lint here
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Generates clippy code that detects the offending pattern
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // ./tests/ui/my_lint.rs
+    /// fn foo() {
+    ///     // detect the following pattern
+    ///     #[clippy::author]
+    ///     if x == 42 {
+    ///         // but ignore everything from here on
+    ///         #![clippy::author = "ignore"]
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Running `TESTNAME=ui/my_lint cargo uitest` will produce
+    /// a `./tests/ui/new_lint.stdout` file with the generated code:
+    ///
+    /// ```rust
+    /// // ./tests/ui/new_lint.stdout
+    /// if_chain! {
+    ///     if let ExprKind::If(ref cond, ref then, None) = item.node,
+    ///     if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.node,
+    ///     if let ExprKind::Path(ref path) = left.node,
+    ///     if let ExprKind::Lit(ref lit) = right.node,
+    ///     if let LitKind::Int(42, _) = lit.node,
+    ///     then {
+    ///         // report your lint here
+    ///     }
+    /// }
+    /// ```
     pub LINT_AUTHOR,
     internal_warn,
     "helper for writing lints"
 }
 
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(LINT_AUTHOR)
-    }
-}
+declare_lint_pass!(Author => [LINT_AUTHOR]);
 
 fn prelude() {
     println!("if_chain! {{");
@@ -68,9 +61,9 @@ fn done() {
     println!("}}");
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
-    fn check_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
-        if !has_attr(&item.attrs) {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Author {
+    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
+        if !has_attr(cx.sess(), &item.attrs) {
             return;
         }
         prelude();
@@ -78,8 +71,8 @@ fn check_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
         done();
     }
 
-    fn check_impl_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) {
-        if !has_attr(&item.attrs) {
+    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) {
+        if !has_attr(cx.sess(), &item.attrs) {
             return;
         }
         prelude();
@@ -87,8 +80,8 @@ fn check_impl_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Impl
         done();
     }
 
-    fn check_trait_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
-        if !has_attr(&item.attrs) {
+    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
+        if !has_attr(cx.sess(), &item.attrs) {
             return;
         }
         prelude();
@@ -96,17 +89,17 @@ fn check_trait_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Tra
         done();
     }
 
-    fn check_variant(&mut self, _cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, generics: &hir::Generics) {
-        if !has_attr(&var.node.attrs) {
+    fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, generics: &hir::Generics) {
+        if !has_attr(cx.sess(), &var.node.attrs) {
             return;
         }
         prelude();
-        PrintVisitor::new("var").visit_variant(var, generics, DUMMY_NODE_ID);
+        PrintVisitor::new("var").visit_variant(var, generics, hir::DUMMY_HIR_ID);
         done();
     }
 
-    fn check_struct_field(&mut self, _cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
-        if !has_attr(&field.attrs) {
+    fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) {
+        if !has_attr(cx.sess(), &field.attrs) {
             return;
         }
         prelude();
@@ -114,8 +107,8 @@ fn check_struct_field(&mut self, _cx: &LateContext<'a, 'tcx>, field: &'tcx hir::
         done();
     }
 
-    fn check_expr(&mut self, _cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        if !has_attr(&expr.attrs) {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
+        if !has_attr(cx.sess(), &expr.attrs) {
             return;
         }
         prelude();
@@ -123,8 +116,8 @@ fn check_expr(&mut self, _cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
         done();
     }
 
-    fn check_arm(&mut self, _cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
-        if !has_attr(&arm.attrs) {
+    fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
+        if !has_attr(cx.sess(), &arm.attrs) {
             return;
         }
         prelude();
@@ -132,8 +125,8 @@ fn check_arm(&mut self, _cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
         done();
     }
 
-    fn check_stmt(&mut self, _cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
-        if !has_attr(stmt.node.attrs()) {
+    fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
+        if !has_attr(cx.sess(), stmt.node.attrs()) {
             return;
         }
         prelude();
@@ -141,8 +134,8 @@ fn check_stmt(&mut self, _cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
         done();
     }
 
-    fn check_foreign_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) {
-        if !has_attr(&item.attrs) {
+    fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) {
+        if !has_attr(cx.sess(), &item.attrs) {
             return;
         }
         prelude();
@@ -154,7 +147,7 @@ fn check_foreign_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::F
 impl PrintVisitor {
     fn new(s: &'static str) -> Self {
         Self {
-            ids: HashMap::new(),
+            ids: FxHashMap::default(),
             current: s.to_owned(),
         }
     }
@@ -186,13 +179,40 @@ fn print_qpath(&mut self, path: &QPath) {
 struct PrintVisitor {
     /// Fields are the current index that needs to be appended to pattern
     /// binding names
-    ids: HashMap<&'static str, usize>,
+    ids: FxHashMap<&'static str, usize>,
     /// the name that needs to be destructured
     current: String,
 }
 
 impl<'tcx> Visitor<'tcx> for PrintVisitor {
+    #[allow(clippy::too_many_lines)]
     fn visit_expr(&mut self, expr: &Expr) {
+        // handle if desugarings
+        // TODO add more desugarings here
+        if let Some((cond, then, opt_else)) = higher::if_block(&expr) {
+            let cond_pat = self.next("cond");
+            let then_pat = self.next("then");
+            if let Some(else_) = opt_else {
+                let else_pat = self.next("else_");
+                println!(
+                    "    if let Some((ref {}, ref {}, Some({}))) = higher::if_block(&{});",
+                    cond_pat, then_pat, else_pat, self.current
+                );
+                self.current = else_pat;
+                self.visit_expr(else_);
+            } else {
+                println!(
+                    "    if let Some((ref {}, ref {}, None)) = higher::if_block(&{});",
+                    cond_pat, then_pat, self.current
+                );
+            }
+            self.current = cond_pat;
+            self.visit_expr(cond);
+            self.current = then_pat;
+            self.visit_expr(then);
+            return;
+        }
+
         print!("    if let ExprKind::");
         let current = format!("{}.node", self.current);
         match expr.node {
@@ -240,7 +260,10 @@ fn visit_expr(&mut self, expr: &Expr) {
                 let op_pat = self.next("op");
                 let left_pat = self.next("left");
                 let right_pat = self.next("right");
-                println!("Binary(ref {}, ref {}, ref {}) = {};", op_pat, left_pat, right_pat, current);
+                println!(
+                    "Binary(ref {}, ref {}, ref {}) = {};",
+                    op_pat, left_pat, right_pat, current
+                );
                 println!("    if BinOpKind::{:?} == {}.node;", op.node, op_pat);
                 self.current = left_pat;
                 self.visit_expr(left);
@@ -259,6 +282,7 @@ fn visit_expr(&mut self, expr: &Expr) {
                 match lit.node {
                     LitKind::Bool(val) => println!("    if let LitKind::Bool({:?}) = {}.node;", val, lit_pat),
                     LitKind::Char(c) => println!("    if let LitKind::Char({:?}) = {}.node;", c, lit_pat),
+                    LitKind::Err(val) => println!("    if let LitKind::Err({}) = {}.node;", val, lit_pat),
                     LitKind::Byte(b) => println!("    if let LitKind::Byte({}) = {}.node;", b, lit_pat),
                     // FIXME: also check int type
                     LitKind::Int(i, _) => println!("    if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
@@ -298,27 +322,14 @@ fn visit_expr(&mut self, expr: &Expr) {
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
-            ExprKind::If(ref cond, ref then, ref opt_else) => {
-                let cond_pat = self.next("cond");
-                let then_pat = self.next("then");
-                if let Some(ref else_) = *opt_else {
-                    let else_pat = self.next("else_");
-                    println!("If(ref {}, ref {}, Some(ref {})) = {};", cond_pat, then_pat, else_pat, current);
-                    self.current = else_pat;
-                    self.visit_expr(else_);
-                } else {
-                    println!("If(ref {}, ref {}, None) = {};", cond_pat, then_pat, current);
-                }
-                self.current = cond_pat;
-                self.visit_expr(cond);
-                self.current = then_pat;
-                self.visit_expr(then);
-            },
             ExprKind::While(ref cond, ref body, _) => {
                 let cond_pat = self.next("cond");
                 let body_pat = self.next("body");
                 let label_pat = self.next("label");
-                println!("While(ref {}, ref {}, ref {}) = {};", cond_pat, body_pat, label_pat, current);
+                println!(
+                    "While(ref {}, ref {}, ref {}) = {};",
+                    cond_pat, body_pat, label_pat, current
+                );
                 self.current = cond_pat;
                 self.visit_expr(cond);
                 self.current = body_pat;
@@ -345,9 +356,15 @@ fn visit_expr(&mut self, expr: &Expr) {
                     self.visit_expr(&arm.body);
                     if let Some(ref guard) = arm.guard {
                         let guard_pat = self.next("guard");
-                        println!("    if let Some(ref {}) = {}[{}].guard", guard_pat, arms_pat, i);
-                        self.current = guard_pat;
-                        self.visit_expr(guard);
+                        println!("    if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
+                        match guard {
+                            hir::Guard::If(ref if_expr) => {
+                                let if_expr_pat = self.next("expr");
+                                println!("    if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
+                                self.current = if_expr_pat;
+                                self.visit_expr(if_expr);
+                            },
+                        }
                     }
                     println!("    if {}[{}].pats.len() == {};", arms_pat, i, arm.pats.len());
                     for (j, pat) in arm.pats.iter().enumerate() {
@@ -385,7 +402,10 @@ fn visit_expr(&mut self, expr: &Expr) {
                 let op_pat = self.next("op");
                 let target_pat = self.next("target");
                 let value_pat = self.next("value");
-                println!("AssignOp(ref {}, ref {}, ref {}) = {};", op_pat, target_pat, value_pat, current);
+                println!(
+                    "AssignOp(ref {}, ref {}, ref {}) = {};",
+                    op_pat, target_pat, value_pat, current
+                );
                 println!("    if BinOpKind::{:?} == {}.node;", op.node, op_pat);
                 self.current = target_pat;
                 self.visit_expr(target);
@@ -438,13 +458,15 @@ fn visit_expr(&mut self, expr: &Expr) {
                 println!("Again(ref {}) = {};", destination_pat, current);
                 // FIXME: implement label printing
             },
-            ExprKind::Ret(ref opt_value) => if let Some(ref value) = *opt_value {
-                let value_pat = self.next("value");
-                println!("Ret(Some(ref {})) = {};", value_pat, current);
-                self.current = value_pat;
-                self.visit_expr(value);
-            } else {
-                println!("Ret(None) = {};", current);
+            ExprKind::Ret(ref opt_value) => {
+                if let Some(ref value) = *opt_value {
+                    let value_pat = self.next("value");
+                    println!("Ret(Some(ref {})) = {};", value_pat, current);
+                    self.current = value_pat;
+                    self.visit_expr(value);
+                } else {
+                    println!("Ret(None) = {};", current);
+                }
             },
             ExprKind::InlineAsm(_, ref _input, ref _output) => {
                 println!("InlineAsm(_, ref input, ref output) = {};", current);
@@ -457,10 +479,7 @@ fn visit_expr(&mut self, expr: &Expr) {
                     let base_pat = self.next("base");
                     println!(
                         "Struct(ref {}, ref {}, Some(ref {})) = {};",
-                        path_pat,
-                        fields_pat,
-                        base_pat,
-                        current
+                        path_pat, fields_pat, base_pat, current
                     );
                     self.current = base_pat;
                     self.visit_expr(base);
@@ -480,15 +499,25 @@ fn visit_expr(&mut self, expr: &Expr) {
                 self.current = value_pat;
                 self.visit_expr(value);
             },
+            ExprKind::Err => {
+                println!("Err = {}", current);
+            },
+            ExprKind::DropTemps(ref expr) => {
+                let expr_pat = self.next("expr");
+                println!("DropTemps(ref {}) = {};", expr_pat, current);
+                self.current = expr_pat;
+                self.visit_expr(expr);
+            },
         }
     }
 
+    #[allow(clippy::too_many_lines)]
     fn visit_pat(&mut self, pat: &Pat) {
         print!("    if let PatKind::");
         let current = format!("{}.node", self.current);
         match pat.node {
             PatKind::Wild => println!("Wild = {};", current),
-            PatKind::Binding(anno, _, ident, ref sub) => {
+            PatKind::Binding(anno, .., ident, ref sub) => {
                 let anno_pat = match anno {
                     BindingAnnotation::Unannotated => "BindingAnnotation::Unannotated",
                     BindingAnnotation::Mutable => "BindingAnnotation::Mutable",
@@ -498,27 +527,36 @@ fn visit_pat(&mut self, pat: &Pat) {
                 let name_pat = self.next("name");
                 if let Some(ref sub) = *sub {
                     let sub_pat = self.next("sub");
-                    println!("Binding({}, _, {}, Some(ref {})) = {};", anno_pat, name_pat, sub_pat, current);
+                    println!(
+                        "Binding({}, _, {}, Some(ref {})) = {};",
+                        anno_pat, name_pat, sub_pat, current
+                    );
                     self.current = sub_pat;
                     self.visit_pat(sub);
                 } else {
                     println!("Binding({}, _, {}, None) = {};", anno_pat, name_pat, current);
                 }
                 println!("    if {}.node.as_str() == \"{}\";", name_pat, ident.as_str());
-            }
+            },
             PatKind::Struct(ref path, ref fields, ignore) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
-                println!("Struct(ref {}, ref {}, {}) = {};", path_pat, fields_pat, ignore, current);
+                println!(
+                    "Struct(ref {}, ref {}, {}) = {};",
+                    path_pat, fields_pat, ignore, current
+                );
                 self.current = path_pat;
                 self.print_qpath(path);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
-            }
+            },
             PatKind::TupleStruct(ref path, ref fields, skip_pos) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
-                println!("TupleStruct(ref {}, ref {}, {:?}) = {};", path_pat, fields_pat, skip_pos, current);
+                println!(
+                    "TupleStruct(ref {}, ref {}, {:?}) = {};",
+                    path_pat, fields_pat, skip_pos, current
+                );
                 self.current = path_pat;
                 self.print_qpath(path);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
@@ -529,13 +567,13 @@ fn visit_pat(&mut self, pat: &Pat) {
                 println!("Path(ref {}) = {};", path_pat, current);
                 self.current = path_pat;
                 self.print_qpath(path);
-            }
+            },
             PatKind::Tuple(ref fields, skip_pos) => {
                 let fields_pat = self.next("fields");
                 println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
-            }
+            },
             PatKind::Box(ref pat) => {
                 let pat_pat = self.next("pat");
                 println!("Box(ref {}) = {};", pat_pat, current);
@@ -553,22 +591,28 @@ fn visit_pat(&mut self, pat: &Pat) {
                 println!("Lit(ref {}) = {}", lit_expr_pat, current);
                 self.current = lit_expr_pat;
                 self.visit_expr(lit_expr);
-            }
+            },
             PatKind::Range(ref start, ref end, end_kind) => {
                 let start_pat = self.next("start");
                 let end_pat = self.next("end");
-                println!("Range(ref {}, ref {}, RangeEnd::{:?}) = {};", start_pat, end_pat, end_kind, current);
+                println!(
+                    "Range(ref {}, ref {}, RangeEnd::{:?}) = {};",
+                    start_pat, end_pat, end_kind, current
+                );
                 self.current = start_pat;
                 self.visit_expr(start);
                 self.current = end_pat;
                 self.visit_expr(end);
-            }
+            },
             PatKind::Slice(ref start, ref middle, ref end) => {
                 let start_pat = self.next("start");
                 let end_pat = self.next("end");
                 if let Some(ref middle) = middle {
                     let middle_pat = self.next("middle");
-                    println!("Slice(ref {}, Some(ref {}), ref {}) = {};", start_pat, middle_pat, end_pat, current);
+                    println!(
+                        "Slice(ref {}, Some(ref {}), ref {}) = {};",
+                        start_pat, middle_pat, end_pat, current
+                    );
                     self.current = middle_pat;
                     self.visit_pat(middle);
                 } else {
@@ -584,7 +628,7 @@ fn visit_pat(&mut self, pat: &Pat) {
                     self.current = format!("{}[{}]", end_pat, i);
                     self.visit_pat(pat);
                 }
-            }
+            },
         }
     }
 
@@ -592,35 +636,26 @@ fn visit_stmt(&mut self, s: &Stmt) {
         print!("    if let StmtKind::");
         let current = format!("{}.node", self.current);
         match s.node {
-            // Could be an item or a local (let) binding:
-            StmtKind::Decl(ref decl, _) => {
-                let decl_pat = self.next("decl");
-                println!("Decl(ref {}, _) = {}", decl_pat, current);
-                print!("    if let DeclKind::");
-                let current = format!("{}.node", decl_pat);
-                match decl.node {
-                    // A local (let) binding:
-                    DeclKind::Local(ref local) => {
-                        let local_pat = self.next("local");
-                        println!("Local(ref {}) = {};", local_pat, current);
-                        if let Some(ref init) = local.init {
-                            let init_pat = self.next("init");
-                            println!("    if let Some(ref {}) = {}.init", init_pat, local_pat);
-                            self.current = init_pat;
-                            self.visit_expr(init);
-                        }
-                        self.current = format!("{}.pat", local_pat);
-                        self.visit_pat(&local.pat);
-                    },
-                    // An item binding:
-                    DeclKind::Item(_) => {
-                        println!("Item(item_id) = {};", current);
-                    },
+            // A local (let) binding:
+            StmtKind::Local(ref local) => {
+                let local_pat = self.next("local");
+                println!("Local(ref {}) = {};", local_pat, current);
+                if let Some(ref init) = local.init {
+                    let init_pat = self.next("init");
+                    println!("    if let Some(ref {}) = {}.init;", init_pat, local_pat);
+                    self.current = init_pat;
+                    self.visit_expr(init);
                 }
-            }
+                self.current = format!("{}.pat", local_pat);
+                self.visit_pat(&local.pat);
+            },
+            // An item binding:
+            StmtKind::Item(_) => {
+                println!("Item(item_id) = {};", current);
+            },
 
             // Expr without trailing semi-colon (must have unit type):
-            StmtKind::Expr(ref e, _) => {
+            StmtKind::Expr(ref e) => {
                 let e_pat = self.next("e");
                 println!("Expr(ref {}, _) = {}", e_pat, current);
                 self.current = e_pat;
@@ -628,7 +663,7 @@ fn visit_stmt(&mut self, s: &Stmt) {
             },
 
             // Expr with trailing semi-colon (may have any type):
-            StmtKind::Semi(ref e, _) => {
+            StmtKind::Semi(ref e) => {
                 let e_pat = self.next("e");
                 println!("Semi(ref {}, _) = {}", e_pat, current);
                 self.current = e_pat;
@@ -642,8 +677,8 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-fn has_attr(attrs: &[Attribute]) -> bool {
-    get_attr(attrs, "author").count() > 0
+fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
+    get_attr(sess, attrs, "author").count() > 0
 }
 
 fn desugaring_name(des: hir::MatchSource) -> String {
@@ -652,7 +687,15 @@ fn desugaring_name(des: hir::MatchSource) -> String {
         hir::MatchSource::TryDesugar => "MatchSource::TryDesugar".to_string(),
         hir::MatchSource::WhileLetDesugar => "MatchSource::WhileLetDesugar".to_string(),
         hir::MatchSource::Normal => "MatchSource::Normal".to_string(),
-        hir::MatchSource::IfLetDesugar { contains_else_clause } => format!("MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", contains_else_clause),
+        hir::MatchSource::IfLetDesugar { contains_else_clause } => format!(
+            "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}",
+            contains_else_clause
+        ),
+        hir::MatchSource::IfDesugar { contains_else_clause } => format!(
+            "MatchSource::IfDesugar {{ contains_else_clause: {} }}",
+            contains_else_clause
+        ),
+        hir::MatchSource::AwaitDesugar => "MatchSource::AwaitDesugar".to_string(),
     }
 }
 
@@ -666,13 +709,15 @@ fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
 
 fn print_path(path: &QPath, first: &mut bool) {
     match *path {
-        QPath::Resolved(_, ref path) => for segment in &path.segments {
-            if *first {
-                *first = false;
-            } else {
-                print!(", ");
+        QPath::Resolved(_, ref path) => {
+            for segment in &path.segments {
+                if *first {
+                    *first = false;
+                } else {
+                    print!(", ");
+                }
+                print!("{:?}", segment.ident.as_str());
             }
-            print!("{:?}", segment.ident.as_str());
         },
         QPath::TypeRelative(ref ty, ref segment) => match ty.node {
             hir::TyKind::Path(ref inner_path) => {
diff --git a/clippy_lints/src/utils/camel_case.rs b/clippy_lints/src/utils/camel_case.rs
new file mode 100644 (file)
index 0000000..5b124dd
--- /dev/null
@@ -0,0 +1,113 @@
+/// Returns the index of the character after the first camel-case component of `s`.
+pub fn until(s: &str) -> usize {
+    let mut iter = s.char_indices();
+    if let Some((_, first)) = iter.next() {
+        if !first.is_uppercase() {
+            return 0;
+        }
+    } else {
+        return 0;
+    }
+    let mut up = true;
+    let mut last_i = 0;
+    for (i, c) in iter {
+        if up {
+            if c.is_lowercase() {
+                up = false;
+            } else {
+                return last_i;
+            }
+        } else if c.is_uppercase() {
+            up = true;
+            last_i = i;
+        } else if !c.is_lowercase() {
+            return i;
+        }
+    }
+    if up {
+        last_i
+    } else {
+        s.len()
+    }
+}
+
+/// Returns index of the last camel-case component of `s`.
+pub fn from(s: &str) -> usize {
+    let mut iter = s.char_indices().rev();
+    if let Some((_, first)) = iter.next() {
+        if !first.is_lowercase() {
+            return s.len();
+        }
+    } else {
+        return s.len();
+    }
+    let mut down = true;
+    let mut last_i = s.len();
+    for (i, c) in iter {
+        if down {
+            if c.is_uppercase() {
+                down = false;
+                last_i = i;
+            } else if !c.is_lowercase() {
+                return last_i;
+            }
+        } else if c.is_lowercase() {
+            down = true;
+        } else {
+            return last_i;
+        }
+    }
+    last_i
+}
+
+#[cfg(test)]
+mod test {
+    use super::{from, until};
+
+    #[test]
+    fn from_full() {
+        assert_eq!(from("AbcDef"), 0);
+        assert_eq!(from("Abc"), 0);
+    }
+
+    #[test]
+    fn from_partial() {
+        assert_eq!(from("abcDef"), 3);
+        assert_eq!(from("aDbc"), 1);
+    }
+
+    #[test]
+    fn from_not() {
+        assert_eq!(from("AbcDef_"), 7);
+        assert_eq!(from("AbcDD"), 5);
+    }
+
+    #[test]
+    fn from_caps() {
+        assert_eq!(from("ABCD"), 4);
+    }
+
+    #[test]
+    fn until_full() {
+        assert_eq!(until("AbcDef"), 6);
+        assert_eq!(until("Abc"), 3);
+    }
+
+    #[test]
+    fn until_not() {
+        assert_eq!(until("abcDef"), 0);
+        assert_eq!(until("aDbc"), 0);
+    }
+
+    #[test]
+    fn until_partial() {
+        assert_eq!(until("AbcDef_"), 6);
+        assert_eq!(until("CallTypeC"), 8);
+        assert_eq!(until("AbcDD"), 3);
+    }
+
+    #[test]
+    fn until_caps() {
+        assert_eq!(until("ABCD"), 0);
+    }
+}
index 35f41d400ad8417db4f416f14f3ed81d908c3de4..31e20f37e20dfab2df53f26d9dfcdbd5157d4c50 100644 (file)
@@ -1,6 +1,6 @@
 //! Utility functions about comparison operators.
 
-#![deny(missing_docs_in_private_items)]
+#![deny(clippy::missing_docs_in_private_items)]
 
 use rustc::hir::{BinOpKind, Expr};
 
index a27013344d8e9586f8eba8a1b1dcd8e34820a0c6..1c71a76f159054ac7145aef1385be95ff0080d63 100644 (file)
@@ -1,28 +1,30 @@
 //! Read configurations files.
 
-#![deny(missing_docs_in_private_items)]
+#![deny(clippy::missing_docs_in_private_items)]
 
+use crate::utils::sym;
 use lazy_static::lazy_static;
-use std::{env, fmt, fs, io, path};
+use std::default::Default;
 use std::io::Read;
-use syntax::{ast, codemap};
-use toml;
 use std::sync::Mutex;
+use std::{env, fmt, fs, io, path};
+use syntax::{ast, source_map};
+use toml;
 
-/// Get the configuration file from arguments.
-pub fn file_from_args(
-    args: &[codemap::Spanned<ast::NestedMetaItemKind>],
-) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
-    for arg in args.iter().filter_map(|a| a.meta_item()) {
-        if arg.name() == "conf_file" {
+/// Gets the configuration file from arguments.
+pub fn file_from_args(args: &[ast::NestedMetaItem]) -> Result<Option<path::PathBuf>, (&'static str, source_map::Span)> {
+    for arg in args.iter().filter_map(syntax::ast::NestedMetaItem::meta_item) {
+        if arg.check_name(*sym::conf_file) {
             return match arg.node {
                 ast::MetaItemKind::Word | ast::MetaItemKind::List(_) => {
                     Err(("`conf_file` must be a named value", arg.span))
                 },
-                ast::MetaItemKind::NameValue(ref value) => if let ast::LitKind::Str(ref file, _) = value.node {
-                    Ok(Some(file.to_string().into()))
-                } else {
-                    Err(("`conf_file` value must be a string", value.span))
+                ast::MetaItemKind::NameValue(ref value) => {
+                    if let ast::LitKind::Str(ref file, _) = value.node {
+                        Ok(Some(file.to_string().into()))
+                    } else {
+                        Err(("`conf_file` value must be a string", value.span))
+                    }
                 },
             };
         }
@@ -38,17 +40,6 @@ pub enum Error {
     Io(io::Error),
     /// Not valid toml or doesn't fit the expected conf format
     Toml(String),
-    /// Type error.
-    Type(
-        /// The name of the key.
-        &'static str,
-        /// The expected type.
-        &'static str,
-        /// The type we got instead.
-        &'static str,
-    ),
-    /// There is an unknown key is the file.
-    UnknownKey(String),
 }
 
 impl fmt::Display for Error {
@@ -56,10 +47,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
         match *self {
             Error::Io(ref err) => err.fmt(f),
             Error::Toml(ref err) => err.fmt(f),
-            Error::Type(key, expected, got) => {
-                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
-            },
-            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
         }
     }
 }
@@ -77,17 +64,8 @@ fn from(e: io::Error) -> Self {
 macro_rules! define_Conf {
     ($(#[$doc: meta] ($rust_name: ident, $rust_name_str: expr, $default: expr => $($ty: tt)+),)+) => {
         pub use self::helpers::Conf;
-        // FIXME(mati865): remove #[allow(rust_2018_idioms)] when it's fixed:
-        //
-        // warning: `extern crate` is not idiomatic in the new edition
-        //    --> src/utils/conf.rs:82:22
-        //     |
-        // 82  |               #[derive(Deserialize)]
-        //     |                        ^^^^^^^^^^^ help: convert it to a `use`
-        //
-        #[allow(rust_2018_idioms)]
         mod helpers {
-            use serde_derive::Deserialize;
+            use serde::Deserialize;
             /// Type used to store lint configuration.
             #[derive(Deserialize)]
             #[serde(rename_all="kebab-case", deny_unknown_fields)]
@@ -131,8 +109,10 @@ fn $rust_name() -> define_Conf!(TY $($ty)+) {
 define_Conf! {
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
     (blacklisted_names, "blacklisted_names", ["foo", "bar", "baz", "quux"] => Vec<String>),
-    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
-    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", 25 => u64),
+    /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
+    (cognitive_complexity_threshold, "cognitive_complexity_threshold", 25 => u64),
+    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
+    (cyclomatic_complexity_threshold, "cyclomatic_complexity_threshold", None => Option<u64>),
     /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
     (doc_valid_idents, "doc_valid_idents", [
         "KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
@@ -149,6 +129,7 @@ fn $rust_name() -> define_Conf!(TY $($ty)+) {
         "iOS", "macOS",
         "TeX", "LaTeX", "BibTeX", "BibLaTeX",
         "MinGW",
+        "CamelCase",
     ] => Vec<String>),
     /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
     (too_many_arguments_threshold, "too_many_arguments_threshold", 7 => u64),
@@ -160,7 +141,7 @@ fn $rust_name() -> define_Conf!(TY $($ty)+) {
     (too_large_for_stack, "too_large_for_stack", 200 => u64),
     /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
     (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64),
-    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion
+    /// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
     (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64),
     /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
     (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64),
@@ -168,6 +149,14 @@ fn $rust_name() -> define_Conf!(TY $($ty)+) {
     (literal_representation_threshold, "literal_representation_threshold", 16384 => u64),
     /// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
     (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
+    /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
+    (too_many_lines_threshold, "too_many_lines_threshold", 100 => u64),
+}
+
+impl Default for Conf {
+    fn default() -> Self {
+        toml::from_str("").expect("we never error on empty config files")
+    }
 }
 
 /// Search for the configuration file.
@@ -175,8 +164,13 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
     /// Possible filename to search for.
     const CONFIG_FILE_NAMES: [&str; 2] = [".clippy.toml", "clippy.toml"];
 
-    let mut current = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
-
+    // Start looking for a config file in CLIPPY_CONF_DIR, or failing that, CARGO_MANIFEST_DIR.
+    // If neither of those exist, use ".".
+    let mut current = path::PathBuf::from(
+        env::var("CLIPPY_CONF_DIR")
+            .or_else(|_| env::var("CARGO_MANIFEST_DIR"))
+            .unwrap_or_else(|_| ".".to_string()),
+    );
     loop {
         for config_file_name in &CONFIG_FILE_NAMES {
             let config_file = current.join(config_file_name);
@@ -186,8 +180,10 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
                 Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                 // Return the error if it's something other than `NotFound`; otherwise we didn't
                 // find the project file yet, and continue searching.
-                Err(e) => if e.kind() != io::ErrorKind::NotFound {
-                    return Err(e);
+                Err(e) => {
+                    if e.kind() != io::ErrorKind::NotFound {
+                        return Err(e);
+                    }
                 },
                 _ => (),
             }
@@ -204,7 +200,7 @@ pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
 ///
 /// Used internally for convenience
 fn default(errors: Vec<Error>) -> (Conf, Vec<Error>) {
-    (toml::from_str("").expect("we never error on empty config files"), errors)
+    (Conf::default(), errors)
 }
 
 /// Read the `toml` configuration file.
@@ -230,26 +226,26 @@ pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
         Err(err) => return default(vec![err.into()]),
     };
 
-    assert!(
-        ERRORS
-            .lock()
-            .expect("no threading -> mutex always safe")
-            .is_empty()
-    );
+    assert!(ERRORS.lock().expect("no threading -> mutex always safe").is_empty());
     match toml::from_str(&file) {
-        Ok(toml) => (
-            toml,
-            ERRORS
-                .lock()
-                .expect("no threading -> mutex always safe")
-                .split_off(0),
-        ),
+        Ok(toml) => {
+            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
+
+            let toml_ref: &Conf = &toml;
+
+            let cyc_field: Option<u64> = toml_ref.cyclomatic_complexity_threshold;
+
+            if cyc_field.is_some() {
+                let cyc_err = "found deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead.".to_string();
+                errors.push(Error::Toml(cyc_err));
+            }
+
+            (toml, errors)
+        },
         Err(e) => {
-            let mut errors = ERRORS
-                .lock()
-                .expect("no threading -> mutex always safe")
-                .split_off(0);
+            let mut errors = ERRORS.lock().expect("no threading -> mutex always safe").split_off(0);
             errors.push(Error::Toml(e.to_string()));
+
             default(errors)
         },
     }
index f59716268a064cd57704c242f37380b5cff1a605..522932f054d894eef06d81b7a53203fc255f9d89 100644 (file)
@@ -1,26 +1,13 @@
 //! This module contains some useful constants.
 
-#![deny(missing_docs_in_private_items)]
+#![deny(clippy::missing_docs_in_private_items)]
 
 /// List of the built-in types names.
 ///
 /// See also [the reference][reference-types] for a list of such types.
 ///
-/// [reference-types]: https://doc.rust-lang.org/reference.html#types
+/// [reference-types]: https://doc.rust-lang.org/reference/types.html
 pub const BUILTIN_TYPES: &[&str] = &[
-    "i8",
-    "u8",
-    "i16",
-    "u16",
-    "i32",
-    "u32",
-    "i64",
-    "u64",
-    "isize",
-    "usize",
-    "f32",
-    "f64",
-    "bool",
-    "str",
-    "char",
+    "i8", "u8", "i16", "u16", "i32", "u32", "i64", "u64", "i128", "u128", "isize", "usize", "f32", "f64", "bool",
+    "str", "char",
 ];
diff --git a/clippy_lints/src/utils/diagnostics.rs b/clippy_lints/src/utils/diagnostics.rs
new file mode 100644 (file)
index 0000000..5be0a67
--- /dev/null
@@ -0,0 +1,205 @@
+//! Clippy wrappers around rustc's diagnostic functions.
+
+use rustc::hir::HirId;
+use rustc::lint::{LateContext, Lint, LintContext};
+use rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart, SuggestionStyle};
+use std::env;
+use syntax::errors::DiagnosticBuilder;
+use syntax::source_map::{MultiSpan, Span};
+
+/// Wrapper around `DiagnosticBuilder` that adds a link to Clippy documentation for the emitted lint
+struct DiagnosticWrapper<'a>(DiagnosticBuilder<'a>);
+
+impl<'a> Drop for DiagnosticWrapper<'a> {
+    fn drop(&mut self) {
+        self.0.emit();
+    }
+}
+
+impl<'a> DiagnosticWrapper<'a> {
+    fn docs_link(&mut self, lint: &'static Lint) {
+        if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
+            self.0.help(&format!(
+                "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
+                &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
+                    // extract just major + minor version and ignore patch versions
+                    format!("rust-{}", n.rsplitn(2, '.').nth(1).unwrap())
+                }),
+                lint.name_lower().replacen("clippy::", "", 1)
+            ));
+        }
+    }
+}
+
+/// Emit a basic lint message with a `msg` and a `span`.
+///
+/// This is the most primitive of our lint emission methods and can
+/// be a good way to get a new lint started.
+///
+/// Usually it's nicer to provide more context for lint messages.
+/// Be sure the output is understandable when you use this method.
+///
+/// # Example
+///
+/// ```ignore
+/// error: usage of mem::forget on Drop type
+///   --> $DIR/mem_forget.rs:17:5
+///    |
+/// 17 |     std::mem::forget(seven);
+///    |     ^^^^^^^^^^^^^^^^^^^^^^^
+/// ```
+pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
+    DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)).docs_link(lint);
+}
+
+/// Same as `span_lint` but with an extra `help` message.
+///
+/// Use this if you want to provide some general help but
+/// can't provide a specific machine applicable suggestion.
+///
+/// The `help` message is not attached to any `Span`.
+///
+/// # Example
+///
+/// ```ignore
+/// error: constant division of 0.0 with 0.0 will always result in NaN
+///   --> $DIR/zero_div_zero.rs:6:25
+///    |
+/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
+///    |                         ^^^^^^^^^^^^
+///    |
+///    = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
+/// ```
+pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
+    cx: &'a T,
+    lint: &'static Lint,
+    span: Span,
+    msg: &str,
+    help: &str,
+) {
+    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
+    db.0.help(help);
+    db.docs_link(lint);
+}
+
+/// Like `span_lint` but with a `note` section instead of a `help` message.
+///
+/// The `note` message is presented separately from the main lint message
+/// and is attached to a specific span:
+///
+/// # Example
+///
+/// ```ignore
+/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
+///   --> $DIR/drop_forget_ref.rs:10:5
+///    |
+/// 10 |     forget(&SomeStruct);
+///    |     ^^^^^^^^^^^^^^^^^^^
+///    |
+///    = note: `-D clippy::forget-ref` implied by `-D warnings`
+/// note: argument has type &SomeStruct
+///   --> $DIR/drop_forget_ref.rs:10:12
+///    |
+/// 10 |     forget(&SomeStruct);
+///    |            ^^^^^^^^^^^
+/// ```
+pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
+    cx: &'a T,
+    lint: &'static Lint,
+    span: Span,
+    msg: &str,
+    note_span: Span,
+    note: &str,
+) {
+    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
+    if note_span == span {
+        db.0.note(note);
+    } else {
+        db.0.span_note(note_span, note);
+    }
+    db.docs_link(lint);
+}
+
+pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(
+    cx: &'a T,
+    lint: &'static Lint,
+    sp: Span,
+    msg: &str,
+    f: F,
+) where
+    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
+{
+    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
+    f(&mut db.0);
+    db.docs_link(lint);
+}
+
+pub fn span_lint_hir(cx: &LateContext<'_, '_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
+    DiagnosticWrapper(cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg)).docs_link(lint);
+}
+
+pub fn span_lint_hir_and_then(
+    cx: &LateContext<'_, '_>,
+    lint: &'static Lint,
+    hir_id: HirId,
+    sp: Span,
+    msg: &str,
+    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
+) {
+    let mut db = DiagnosticWrapper(cx.tcx.struct_span_lint_hir(lint, hir_id, sp, msg));
+    f(&mut db.0);
+    db.docs_link(lint);
+}
+
+/// Add a span lint with a suggestion on how to fix it.
+///
+/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
+/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
+/// 2)"`.
+///
+/// ```ignore
+/// error: This `.fold` can be more succinctly expressed as `.any`
+/// --> $DIR/methods.rs:390:13
+///     |
+/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
+///     |
+///     = note: `-D fold-any` implied by `-D warnings`
+/// ```
+pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
+    cx: &'a T,
+    lint: &'static Lint,
+    sp: Span,
+    msg: &str,
+    help: &str,
+    sugg: String,
+    applicability: Applicability,
+) {
+    span_lint_and_then(cx, lint, sp, msg, |db| {
+        db.span_suggestion(sp, help, sugg, applicability);
+    });
+}
+
+/// Create a suggestion made from several `span → replacement`.
+///
+/// Note: in the JSON format (used by `compiletest_rs`), the help message will
+/// appear once per
+/// replacement. In human-readable format though, it only appears once before
+/// the whole suggestion.
+pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
+where
+    I: IntoIterator<Item = (Span, String)>,
+{
+    let sugg = CodeSuggestion {
+        substitutions: vec![Substitution {
+            parts: sugg
+                .into_iter()
+                .map(|(span, snippet)| SubstitutionPart { snippet, span })
+                .collect(),
+        }],
+        msg: help_msg,
+        style: SuggestionStyle::ShowCode,
+        applicability: Applicability::Unspecified,
+    };
+    db.suggestions.push(sugg);
+}
index 3931f6c55f9ed0b9bda60de4be8d1d00602152db..610d0c932169b8e90f3e77c1c7074d28c0e7ce29 100644 (file)
@@ -1,15 +1,17 @@
 //! This module contains functions for retrieve the original AST from lowered
 //! `hir`.
 
-#![deny(missing_docs_in_private_items)]
+#![deny(clippy::missing_docs_in_private_items)]
 
+use crate::utils::sym;
+use crate::utils::{is_expn_of, match_def_path, match_qpath, paths, resolve_node};
 use if_chain::if_chain;
-use rustc::{hir, ty};
 use rustc::lint::LateContext;
+use rustc::{hir, ty};
 use syntax::ast;
-use crate::utils::{is_expn_of, match_def_path, match_qpath, opt_def_id, paths, resolve_node};
+use syntax::symbol::Symbol;
 
-/// Convert a hir binary operator to the corresponding `ast` type.
+/// Converts a hir binary operator to the corresponding `ast` type.
 pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
     match op {
         hir::BinOpKind::Eq => ast::BinOpKind::Eq,
@@ -46,9 +48,16 @@ pub struct Range<'a> {
 
 /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
 pub fn range<'a, 'b, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'b hir::Expr) -> Option<Range<'b>> {
+    /// Finds the field named `name` in the field. Always return `Some` for
+    /// convenience.
+    fn get_field(name: Symbol, fields: &[hir::Field]) -> Option<&hir::Expr> {
+        let expr = &fields.iter().find(|field| field.ident.name == name)?.expr;
+
+        Some(expr)
+    }
 
     let def_path = match cx.tables.expr_ty(expr).sty {
-        ty::TyAdt(def, _) => cx.tcx.def_path(def.did),
+        ty::Adt(def, _) => cx.tcx.def_path(def.did),
         _ => return None,
     };
 
@@ -75,21 +84,13 @@ pub fn range<'a, 'b, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'b hir::Expr) -> O
         return None;
     }
 
-    /// Find the field named `name` in the field. Always return `Some` for
-    /// convenience.
-    fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr> {
-        let expr = &fields.iter().find(|field| field.ident.name == name)?.expr;
-
-        Some(expr)
-    }
-
     // The range syntax is expanded to literal paths starting with `core` or `std`
     // depending on
     // `#[no_std]`. Testing both instead of resolving the paths.
 
     match expr.node {
         hir::ExprKind::Path(ref path) => {
-            if match_qpath(path, &paths::RANGE_FULL_STD) || match_qpath(path, &paths::RANGE_FULL) {
+            if match_qpath(path, &*paths::RANGE_FULL_STD) || match_qpath(path, &*paths::RANGE_FULL) {
                 Some(Range {
                     start: None,
                     end: None,
@@ -99,64 +100,69 @@ fn get_field<'a>(name: &str, fields: &'a [hir::Field]) -> Option<&'a hir::Expr>
                 None
             }
         },
-        hir::ExprKind::Call(ref path, ref args) => if let hir::ExprKind::Path(ref path) = path.node {
-            if match_qpath(path, &paths::RANGE_INCLUSIVE_STD_NEW) || match_qpath(path, &paths::RANGE_INCLUSIVE_NEW) {
+        hir::ExprKind::Call(ref path, ref args) => {
+            if let hir::ExprKind::Path(ref path) = path.node {
+                if match_qpath(path, &*paths::RANGE_INCLUSIVE_STD_NEW)
+                    || match_qpath(path, &*paths::RANGE_INCLUSIVE_NEW)
+                {
+                    Some(Range {
+                        start: Some(&args[0]),
+                        end: Some(&args[1]),
+                        limits: ast::RangeLimits::Closed,
+                    })
+                } else {
+                    None
+                }
+            } else {
+                None
+            }
+        },
+        hir::ExprKind::Struct(ref path, ref fields, None) => {
+            if match_qpath(path, &*paths::RANGE_FROM_STD) || match_qpath(path, &*paths::RANGE_FROM) {
                 Some(Range {
-                    start: Some(&args[0]),
-                    end: Some(&args[1]),
+                    start: Some(get_field(*sym::start, fields)?),
+                    end: None,
+                    limits: ast::RangeLimits::HalfOpen,
+                })
+            } else if match_qpath(path, &*paths::RANGE_STD) || match_qpath(path, &*paths::RANGE) {
+                Some(Range {
+                    start: Some(get_field(*sym::start, fields)?),
+                    end: Some(get_field(*sym::end, fields)?),
+                    limits: ast::RangeLimits::HalfOpen,
+                })
+            } else if match_qpath(path, &*paths::RANGE_TO_INCLUSIVE_STD)
+                || match_qpath(path, &*paths::RANGE_TO_INCLUSIVE)
+            {
+                Some(Range {
+                    start: None,
+                    end: Some(get_field(*sym::end, fields)?),
                     limits: ast::RangeLimits::Closed,
                 })
+            } else if match_qpath(path, &*paths::RANGE_TO_STD) || match_qpath(path, &*paths::RANGE_TO) {
+                Some(Range {
+                    start: None,
+                    end: Some(get_field(*sym::end, fields)?),
+                    limits: ast::RangeLimits::HalfOpen,
+                })
             } else {
                 None
             }
-        } else {
-            None
-        },
-        hir::ExprKind::Struct(ref path, ref fields, None) => if match_qpath(path, &paths::RANGE_FROM_STD)
-            || match_qpath(path, &paths::RANGE_FROM)
-        {
-            Some(Range {
-                start: Some(get_field("start", fields)?),
-                end: None,
-                limits: ast::RangeLimits::HalfOpen,
-            })
-        } else if match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE) {
-            Some(Range {
-                start: Some(get_field("start", fields)?),
-                end: Some(get_field("end", fields)?),
-                limits: ast::RangeLimits::HalfOpen,
-            })
-        } else if match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_TO_INCLUSIVE) {
-            Some(Range {
-                start: None,
-                end: Some(get_field("end", fields)?),
-                limits: ast::RangeLimits::Closed,
-            })
-        } else if match_qpath(path, &paths::RANGE_TO_STD) || match_qpath(path, &paths::RANGE_TO) {
-            Some(Range {
-                start: None,
-                end: Some(get_field("end", fields)?),
-                limits: ast::RangeLimits::HalfOpen,
-            })
-        } else {
-            None
         },
         _ => None,
     }
 }
 
-/// Checks if a `let` decl is from a `for` loop desugaring.
-pub fn is_from_for_desugar(decl: &hir::Decl) -> bool {
+/// Checks if a `let` statement is from a `for` loop desugaring.
+pub fn is_from_for_desugar(local: &hir::Local) -> bool {
     // This will detect plain for-loops without an actual variable binding:
     //
     // ```
     // for x in some_vec {
-    //   // do stuff
+    //     // do stuff
     // }
     // ```
     if_chain! {
-        if let hir::DeclKind::Local(ref loc) = decl.node;
-        if let Some(ref expr) = loc.init;
+        if let Some(ref expr) = local.init;
         if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.node;
         then {
             return true;
@@ -168,15 +174,11 @@ pub fn is_from_for_desugar(decl: &hir::Decl) -> bool {
     //
     // ```
     // for _ in vec![()] {
-    //   // anything
+    //     // anything
     // }
     // ```
-    if_chain! {
-        if let hir::DeclKind::Local(ref loc) = decl.node;
-        if let hir::LocalSource::ForLoopDesugar = loc.source;
-        then {
-            return true;
-        }
+    if let hir::LocalSource::ForLoopDesugar = local.source {
+        return true;
     }
 
     false
@@ -192,16 +194,36 @@ pub fn for_loop(expr: &hir::Expr) -> Option<(&hir::Pat, &hir::Expr, &hir::Expr)>
         if let hir::ExprKind::Loop(ref block, _, _) = arms[0].body.node;
         if block.expr.is_none();
         if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
-        if let hir::StmtKind::Decl(ref decl, _) = let_stmt.node;
-        if let hir::DeclKind::Local(ref decl) = decl.node;
-        if let hir::StmtKind::Expr(ref expr, _) = body.node;
+        if let hir::StmtKind::Local(ref local) = let_stmt.node;
+        if let hir::StmtKind::Expr(ref expr) = body.node;
         then {
-            return Some((&*decl.pat, &iterargs[0], expr));
+            return Some((&*local.pat, &iterargs[0], expr));
         }
     }
     None
 }
 
+/// Recover the essential nodes of a desugared if block
+/// `if cond { then } else { els }` becomes `(cond, then, Some(els))`
+pub fn if_block(expr: &hir::Expr) -> Option<(&hir::Expr, &hir::Expr, Option<&hir::Expr>)> {
+    if let hir::ExprKind::Match(ref cond, ref arms, hir::MatchSource::IfDesugar { contains_else_clause }) = expr.node {
+        let cond = if let hir::ExprKind::DropTemps(ref cond) = cond.node {
+            cond
+        } else {
+            panic!("If block desugar must contain DropTemps");
+        };
+        let then = &arms[0].body;
+        let els = if contains_else_clause {
+            Some(&*arms[1].body)
+        } else {
+            None
+        };
+        Some((cond, then, els))
+    } else {
+        None
+    }
+}
+
 /// Represent the pre-expansion arguments of a `vec!` invocation.
 pub enum VecArgs<'a> {
     /// `vec![elem; len]`
@@ -216,14 +238,14 @@ pub fn vec_macro<'e>(cx: &LateContext<'_, '_>, expr: &'e hir::Expr) -> Option<Ve
     if_chain! {
         if let hir::ExprKind::Call(ref fun, ref args) = expr.node;
         if let hir::ExprKind::Path(ref path) = fun.node;
-        if is_expn_of(fun.span, "vec").is_some();
-        if let Some(fun_def_id) = opt_def_id(resolve_node(cx, path, fun.hir_id));
+        if is_expn_of(fun.span, *sym::vec).is_some();
+        if let Some(fun_def_id) = resolve_node(cx, path, fun.hir_id).opt_def_id();
         then {
-            return if match_def_path(cx.tcx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
+            return if match_def_path(cx, fun_def_id, &*paths::VEC_FROM_ELEM) && args.len() == 2 {
                 // `vec![elem; size]` case
                 Some(VecArgs::Repeat(&args[0], &args[1]))
             }
-            else if match_def_path(cx.tcx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
+            else if match_def_path(cx, fun_def_id, &*paths::SLICE_INTO_VEC) && args.len() == 1 {
                 // `vec![a, b, c]` case
                 if_chain! {
                     if let hir::ExprKind::Box(ref boxed) = args[0].node;
index 57486b30d349324a40e02ad7971cdb11afe0d20b..702738b6696cc18a0ac269ab3277c01fbb470cf2 100644 (file)
@@ -1,12 +1,12 @@
-use crate::consts::{constant_simple, constant_context};
-use rustc::lint::*;
+use crate::consts::{constant_context, constant_simple};
+use crate::utils::differing_macro_contexts;
 use rustc::hir::*;
-use rustc::ty::{TypeckTables};
-use std::hash::{Hash, Hasher};
+use rustc::lint::LateContext;
+use rustc::ty::TypeckTables;
 use std::collections::hash_map::DefaultHasher;
+use std::hash::{Hash, Hasher};
 use syntax::ast::Name;
 use syntax::ptr::P;
-use crate::utils::differing_macro_contexts;
 
 /// Type used to check whether two ast are the same. This is different from the
 /// operator
@@ -40,46 +40,52 @@ pub fn ignore_fn(self) -> Self {
         }
     }
 
-    /// Check whether two statements are the same.
+    /// Checks whether two statements are the same.
     pub fn eq_stmt(&mut self, left: &Stmt, right: &Stmt) -> bool {
         match (&left.node, &right.node) {
-            (&StmtKind::Decl(ref l, _), &StmtKind::Decl(ref r, _)) => {
-                if let (&DeclKind::Local(ref l), &DeclKind::Local(ref r)) = (&l.node, &r.node) {
-                    both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
-                } else {
-                    false
-                }
+            (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
+                self.eq_pat(&l.pat, &r.pat)
+                    && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
+                    && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
             },
-            (&StmtKind::Expr(ref l, _), &StmtKind::Expr(ref r, _)) | (&StmtKind::Semi(ref l, _), &StmtKind::Semi(ref r, _)) => {
+            (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
                 self.eq_expr(l, r)
             },
             _ => false,
         }
     }
 
-    /// Check whether two blocks are the same.
+    /// Checks whether two blocks are the same.
     pub fn eq_block(&mut self, left: &Block, right: &Block) -> bool {
         over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
             && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
     }
 
+    #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr, right: &Expr) -> bool {
         if self.ignore_fn && differing_macro_contexts(left.span, right.span) {
             return false;
         }
 
-        if let (Some(l), Some(r)) = (constant_simple(self.cx, self.tables, left), constant_simple(self.cx, self.tables, right)) {
+        if let (Some(l), Some(r)) = (
+            constant_simple(self.cx, self.tables, left),
+            constant_simple(self.cx, self.tables, right),
+        ) {
             if l == r {
                 return true;
             }
         }
 
         match (&left.node, &right.node) {
-            (&ExprKind::AddrOf(l_mut, ref le), &ExprKind::AddrOf(r_mut, ref re)) => l_mut == r_mut && self.eq_expr(le, re),
+            (&ExprKind::AddrOf(l_mut, ref le), &ExprKind::AddrOf(r_mut, ref re)) => {
+                l_mut == r_mut && self.eq_expr(le, re)
+            },
             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
                 both(&li.label, &ri.label, |l, r| l.ident.as_str() == r.ident.as_str())
             },
-            (&ExprKind::Assign(ref ll, ref lr), &ExprKind::Assign(ref rl, ref rr)) => self.eq_expr(ll, rl) && self.eq_expr(lr, rr),
+            (&ExprKind::Assign(ref ll, ref lr), &ExprKind::Assign(ref rl, ref rr)) => {
+                self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
+            },
             (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
                 lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
@@ -98,48 +104,56 @@ pub fn eq_expr(&mut self, left: &Expr, right: &Expr) -> bool {
             (&ExprKind::Call(ref l_fun, ref l_args), &ExprKind::Call(ref r_fun, ref r_args)) => {
                 !self.ignore_fn && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt)) |
-            (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => self.eq_expr(lx, rx) && self.eq_ty(lt, rt),
+            (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
+            | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
+                self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
+            },
             (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
                 l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
             },
-            (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
-            (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => {
-                self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
+            (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
+                self.eq_expr(la, ra) && self.eq_expr(li, ri)
             },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
             (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str())
             },
             (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
-                ls == rs && self.eq_expr(le, re) && over(la, ra, |l, r| {
-                    self.eq_expr(&l.body, &r.body) && both(&l.guard, &r.guard, |l, r| self.eq_expr(l, r))
-                        && over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
-                })
+                ls == rs
+                    && self.eq_expr(le, re)
+                    && over(la, ra, |l, r| {
+                        self.eq_expr(&l.body, &r.body)
+                            && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
+                            && over(&l.pats, &r.pats, |l, r| self.eq_pat(l, r))
+                    })
             },
             (&ExprKind::MethodCall(ref l_path, _, ref l_args), &ExprKind::MethodCall(ref r_path, _, ref r_args)) => {
                 !self.ignore_fn && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
                 let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(ll_id.body));
-                let ll = celcx.expr(&self.cx.tcx.hir.body(ll_id.body).value);
+                let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
                 let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(rl_id.body));
-                let rl = celcx.expr(&self.cx.tcx.hir.body(rl_id.body).value);
+                let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
 
                 self.eq_expr(le, re) && ll == rl
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
             (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
-                self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r))
+                self.eq_qpath(l_path, r_path)
+                    && both(lo, ro, |l, r| self.eq_expr(l, r))
                     && over(lf, rf, |l, r| self.eq_field(l, r))
             },
             (&ExprKind::Tup(ref l_tup), &ExprKind::Tup(ref r_tup)) => self.eq_exprs(l_tup, r_tup),
             (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(ref l), &ExprKind::Array(ref r)) => self.eq_exprs(l, r),
             (&ExprKind::While(ref lc, ref lb, ref ll), &ExprKind::While(ref rc, ref rb, ref rl)) => {
-                self.eq_expr(lc, rc) && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str())
+                self.eq_expr(lc, rc)
+                    && self.eq_block(lb, rb)
+                    && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str())
             },
+            (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
             _ => false,
         }
     }
@@ -152,6 +166,12 @@ fn eq_field(&mut self, left: &Field, right: &Field) -> bool {
         left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
     }
 
+    fn eq_guard(&mut self, left: &Guard, right: &Guard) -> bool {
+        match (left, right) {
+            (Guard::If(l), Guard::If(r)) => self.eq_expr(l, r),
+        }
+    }
+
     fn eq_generic_arg(&mut self, left: &GenericArg, right: &GenericArg) -> bool {
         match (left, right) {
             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => self.eq_lifetime(l_lt, r_lt),
@@ -164,14 +184,14 @@ fn eq_lifetime(&mut self, left: &Lifetime, right: &Lifetime) -> bool {
         left.name == right.name
     }
 
-    /// Check whether two patterns are the same.
+    /// Checks whether two patterns are the same.
     pub fn eq_pat(&mut self, left: &Pat, right: &Pat) -> bool {
         match (&left.node, &right.node) {
             (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
             (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
-            (&PatKind::Binding(ref lb, _, ref li, ref lp), &PatKind::Binding(ref rb, _, ref ri, ref rp)) => {
+            (&PatKind::Binding(ref lb, .., ref li, ref lp), &PatKind::Binding(ref rb, .., ref ri, ref rp)) => {
                 lb == rb && li.name.as_str() == ri.name.as_str() && both(lp, rp, |l, r| self.eq_pat(l, r))
             },
             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
@@ -184,7 +204,8 @@ pub fn eq_pat(&mut self, left: &Pat, right: &Pat) -> bool {
             },
             (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
             (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
-                over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r))
+                over(ls, rs, |l, r| self.eq_pat(l, r))
+                    && over(le, re, |l, r| self.eq_pat(l, r))
                     && both(li, ri, |l, r| self.eq_pat(l, r))
             },
             (&PatKind::Wild, &PatKind::Wild) => true,
@@ -192,6 +213,7 @@ pub fn eq_pat(&mut self, left: &Pat, right: &Pat) -> bool {
         }
     }
 
+    #[allow(clippy::similar_names)]
     fn eq_qpath(&mut self, left: &QPath, right: &QPath) -> bool {
         match (left, right) {
             (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
@@ -215,11 +237,9 @@ fn eq_path_parameters(&mut self, left: &GenericArgs, right: &GenericArgs) -> boo
                 && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
         } else if left.parenthesized && right.parenthesized {
             over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
-                && both(
-                    &Some(&left.bindings[0].ty),
-                    &Some(&right.bindings[0].ty),
-                    |l, r| self.eq_ty(l, r),
-                )
+                && both(&Some(&left.bindings[0].ty), &Some(&right.bindings[0].ty), |l, r| {
+                    self.eq_ty(l, r)
+                })
         } else {
             false
         }
@@ -246,6 +266,7 @@ pub fn eq_ty(&mut self, left: &Ty, right: &Ty) -> bool {
         self.eq_ty_kind(&left.node, &right.node)
     }
 
+    #[allow(clippy::similar_names)]
     pub fn eq_ty_kind(&mut self, left: &TyKind, right: &TyKind) -> bool {
         match (left, right) {
             (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
@@ -254,17 +275,19 @@ pub fn eq_ty_kind(&mut self, left: &TyKind, right: &TyKind) -> bool {
 
                 let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(ll_id.body));
                 self.tables = self.cx.tcx.body_tables(ll_id.body);
-                let ll = celcx.expr(&self.cx.tcx.hir.body(ll_id.body).value);
+                let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
 
                 let mut celcx = constant_context(self.cx, self.cx.tcx.body_tables(rl_id.body));
                 self.tables = self.cx.tcx.body_tables(rl_id.body);
-                let rl = celcx.expr(&self.cx.tcx.hir.body(rl_id.body).value);
+                let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
 
                 let eq_ty = self.eq_ty(lt, rt);
                 self.tables = full_table;
                 eq_ty && ll == rl
             },
-            (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty),
+            (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
+                l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
+            },
             (&TyKind::Rptr(_, ref l_rmut), &TyKind::Rptr(_, ref r_rmut)) => {
                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
             },
@@ -282,28 +305,28 @@ fn eq_type_binding(&mut self, left: &TypeBinding, right: &TypeBinding) -> bool {
 
 fn swap_binop<'a>(binop: BinOpKind, lhs: &'a Expr, rhs: &'a Expr) -> Option<(BinOpKind, &'a Expr, &'a Expr)> {
     match binop {
-        BinOpKind::Add |
-        BinOpKind::Mul |
-        BinOpKind::Eq |
-        BinOpKind::Ne |
-        BinOpKind::BitAnd |
-        BinOpKind::BitXor |
-        BinOpKind::BitOr => Some((binop, rhs, lhs)),
+        BinOpKind::Add
+        | BinOpKind::Mul
+        | BinOpKind::Eq
+        | BinOpKind::Ne
+        | BinOpKind::BitAnd
+        | BinOpKind::BitXor
+        BinOpKind::BitOr => Some((binop, rhs, lhs)),
         BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)),
         BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)),
         BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)),
         BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)),
-        BinOpKind::Shl |
-        BinOpKind::Shr |
-        BinOpKind::Rem |
-        BinOpKind::Sub |
-        BinOpKind::Div |
-        BinOpKind::And |
-        BinOpKind::Or => None,
+        BinOpKind::Shl
+        | BinOpKind::Shr
+        | BinOpKind::Rem
+        | BinOpKind::Sub
+        | BinOpKind::Div
+        | BinOpKind::And
+        BinOpKind::Or => None,
     }
 }
 
-/// Check if the two `Option`s are both `None` or some equal values as per
+/// Checks if the two `Option`s are both `None` or some equal values as per
 /// `eq_fn`.
 fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
 where
@@ -313,7 +336,7 @@ fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
         .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
 }
 
-/// Check if two slices are equal as per `eq_fn`.
+/// Checks if two slices are equal as per `eq_fn`.
 fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
 where
     F: FnMut(&X, &X) -> bool,
@@ -321,7 +344,6 @@ fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
 }
 
-
 /// Type used to hash an ast element. This is different from the `Hash` trait
 /// on ast types as this
 /// trait would consider IDs and spans.
@@ -361,62 +383,52 @@ pub fn hash_block(&mut self, b: &Block) {
             BlockCheckMode::UnsafeBlock(_) => 1,
             BlockCheckMode::PushUnsafeBlock(_) => 2,
             BlockCheckMode::PopUnsafeBlock(_) => 3,
-        }.hash(&mut self.s);
+        }
+        .hash(&mut self.s);
     }
 
-    #[allow(many_single_char_names)]
+    #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
     pub fn hash_expr(&mut self, e: &Expr) {
-        if let Some(e) = constant_simple(self.cx, self.tables, e) {
+        let simple_const = constant_simple(self.cx, self.tables, e);
+
+        // const hashing may result in the same hash as some unrelated node, so add a sort of
+        // discriminant depending on which path we're choosing next
+        simple_const.is_some().hash(&mut self.s);
+
+        if let Some(e) = simple_const {
             return e.hash(&mut self.s);
         }
 
+        std::mem::discriminant(&e.node).hash(&mut self.s);
+
         match e.node {
             ExprKind::AddrOf(m, ref e) => {
-                let c: fn(_, _) -> _ = ExprKind::AddrOf;
-                c.hash(&mut self.s);
                 m.hash(&mut self.s);
                 self.hash_expr(e);
             },
             ExprKind::Continue(i) => {
-                let c: fn(_) -> _ = ExprKind::Continue;
-                c.hash(&mut self.s);
                 if let Some(i) = i.label {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::Yield(ref e) => {
-                let c: fn(_) -> _ = ExprKind::Yield;
-                c.hash(&mut self.s);
-                self.hash_expr(e);
-            },
             ExprKind::Assign(ref l, ref r) => {
-                let c: fn(_, _) -> _ = ExprKind::Assign;
-                c.hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
             ExprKind::AssignOp(ref o, ref l, ref r) => {
-                let c: fn(_, _, _) -> _ = ExprKind::AssignOp;
-                c.hash(&mut self.s);
                 o.hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
             ExprKind::Block(ref b, _) => {
-                let c: fn(_, _) -> _ = ExprKind::Block;
-                c.hash(&mut self.s);
                 self.hash_block(b);
             },
             ExprKind::Binary(op, ref l, ref r) => {
-                let c: fn(_, _, _) -> _ = ExprKind::Binary;
-                c.hash(&mut self.s);
                 op.node.hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
             ExprKind::Break(i, ref j) => {
-                let c: fn(_, _) -> _ = ExprKind::Break;
-                c.hash(&mut self.s);
                 if let Some(i) = i.label {
                     self.hash_name(i.ident.name);
                 }
@@ -424,80 +436,50 @@ pub fn hash_expr(&mut self, e: &Expr) {
                     self.hash_expr(&*j);
                 }
             },
-            ExprKind::Box(ref e) => {
-                let c: fn(_) -> _ = ExprKind::Box;
-                c.hash(&mut self.s);
+            ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e) => {
                 self.hash_expr(e);
             },
             ExprKind::Call(ref fun, ref args) => {
-                let c: fn(_, _) -> _ = ExprKind::Call;
-                c.hash(&mut self.s);
                 self.hash_expr(fun);
                 self.hash_exprs(args);
             },
-            ExprKind::Cast(ref e, ref _ty) => {
-                let c: fn(_, _) -> _ = ExprKind::Cast;
-                c.hash(&mut self.s);
+            ExprKind::Cast(ref e, ref _ty) | ExprKind::Type(ref e, ref _ty) => {
                 self.hash_expr(e);
                 // TODO: _ty
             },
             ExprKind::Closure(cap, _, eid, _, _) => {
-                let c: fn(_, _, _, _, _) -> _ = ExprKind::Closure;
-                c.hash(&mut self.s);
                 match cap {
                     CaptureClause::CaptureByValue => 0,
                     CaptureClause::CaptureByRef => 1,
-                }.hash(&mut self.s);
-                let value = &self.cx.tcx.hir.body(eid).value;
-                self.hash_expr(value);
+                }
+                .hash(&mut self.s);
+                self.hash_expr(&self.cx.tcx.hir().body(eid).value);
             },
             ExprKind::Field(ref e, ref f) => {
-                let c: fn(_, _) -> _ = ExprKind::Field;
-                c.hash(&mut self.s);
                 self.hash_expr(e);
                 self.hash_name(f.name);
             },
             ExprKind::Index(ref a, ref i) => {
-                let c: fn(_, _) -> _ = ExprKind::Index;
-                c.hash(&mut self.s);
                 self.hash_expr(a);
                 self.hash_expr(i);
             },
-            ExprKind::InlineAsm(..) => {
-                let c: fn(_, _, _) -> _ = ExprKind::InlineAsm;
-                c.hash(&mut self.s);
-            },
-            ExprKind::If(ref cond, ref t, ref e) => {
-                let c: fn(_, _, _) -> _ = ExprKind::If;
-                c.hash(&mut self.s);
-                self.hash_expr(cond);
-                self.hash_expr(&**t);
-                if let Some(ref e) = *e {
-                    self.hash_expr(e);
-                }
-            },
+            ExprKind::InlineAsm(..) | ExprKind::Err => {},
             ExprKind::Lit(ref l) => {
-                let c: fn(_) -> _ = ExprKind::Lit;
-                c.hash(&mut self.s);
                 l.hash(&mut self.s);
             },
             ExprKind::Loop(ref b, ref i, _) => {
-                let c: fn(_, _, _) -> _ = ExprKind::Loop;
-                c.hash(&mut self.s);
                 self.hash_block(b);
                 if let Some(i) = *i {
                     self.hash_name(i.ident.name);
                 }
             },
             ExprKind::Match(ref e, ref arms, ref s) => {
-                let c: fn(_, _, _) -> _ = ExprKind::Match;
-                c.hash(&mut self.s);
                 self.hash_expr(e);
 
                 for arm in arms {
                     // TODO: arm.pat?
                     if let Some(ref e) = arm.guard {
-                        self.hash_expr(e);
+                        self.hash_guard(e);
                     }
                     self.hash_expr(&arm.body);
                 }
@@ -505,37 +487,25 @@ pub fn hash_expr(&mut self, e: &Expr) {
                 s.hash(&mut self.s);
             },
             ExprKind::MethodCall(ref path, ref _tys, ref args) => {
-                let c: fn(_, _, _) -> _ = ExprKind::MethodCall;
-                c.hash(&mut self.s);
                 self.hash_name(path.ident.name);
                 self.hash_exprs(args);
             },
             ExprKind::Repeat(ref e, ref l_id) => {
-                let c: fn(_, _) -> _ = ExprKind::Repeat;
-                c.hash(&mut self.s);
                 self.hash_expr(e);
                 let full_table = self.tables;
                 self.tables = self.cx.tcx.body_tables(l_id.body);
-                let value = &self.cx.tcx.hir.body(l_id.body).value;
-                self.hash_expr(value);
+                self.hash_expr(&self.cx.tcx.hir().body(l_id.body).value);
                 self.tables = full_table;
             },
             ExprKind::Ret(ref e) => {
-                let c: fn(_) -> _ = ExprKind::Ret;
-                c.hash(&mut self.s);
                 if let Some(ref e) = *e {
                     self.hash_expr(e);
                 }
             },
             ExprKind::Path(ref qpath) => {
-                let c: fn(_) -> _ = ExprKind::Path;
-                c.hash(&mut self.s);
                 self.hash_qpath(qpath);
             },
             ExprKind::Struct(ref path, ref fields, ref expr) => {
-                let c: fn(_, _, _) -> _ = ExprKind::Struct;
-                c.hash(&mut self.s);
-
                 self.hash_qpath(path);
 
                 for f in fields {
@@ -547,34 +517,14 @@ pub fn hash_expr(&mut self, e: &Expr) {
                     self.hash_expr(e);
                 }
             },
-            ExprKind::Tup(ref tup) => {
-                let c: fn(_) -> _ = ExprKind::Tup;
-                c.hash(&mut self.s);
-                self.hash_exprs(tup);
-            },
-            ExprKind::Type(ref e, ref _ty) => {
-                let c: fn(_, _) -> _ = ExprKind::Type;
-                c.hash(&mut self.s);
-                self.hash_expr(e);
-                // TODO: _ty
+            ExprKind::Tup(ref v) | ExprKind::Array(ref v) => {
+                self.hash_exprs(v);
             },
             ExprKind::Unary(lop, ref le) => {
-                let c: fn(_, _) -> _ = ExprKind::Unary;
-                c.hash(&mut self.s);
-
                 lop.hash(&mut self.s);
                 self.hash_expr(le);
             },
-            ExprKind::Array(ref v) => {
-                let c: fn(_) -> _ = ExprKind::Array;
-                c.hash(&mut self.s);
-
-                self.hash_exprs(v);
-            },
             ExprKind::While(ref cond, ref b, l) => {
-                let c: fn(_, _, _) -> _ = ExprKind::While;
-                c.hash(&mut self.s);
-
                 self.hash_expr(cond);
                 self.hash_block(b);
                 if let Some(l) = l {
@@ -603,7 +553,7 @@ pub fn hash_qpath(&mut self, p: &QPath) {
                 self.hash_name(path.ident.name);
             },
         }
-        // self.cx.tables.qpath_def(p, id).hash(&mut self.s);
+        // self.cx.tables.qpath_res(p, id).hash(&mut self.s);
     }
 
     pub fn hash_path(&mut self, p: &Path) {
@@ -614,25 +564,24 @@ pub fn hash_path(&mut self, p: &Path) {
     }
 
     pub fn hash_stmt(&mut self, b: &Stmt) {
-        match b.node {
-            StmtKind::Decl(ref decl, _) => {
-                let c: fn(_, _) -> _ = StmtKind::Decl;
-                c.hash(&mut self.s);
-
-                if let DeclKind::Local(ref local) = decl.node {
-                    if let Some(ref init) = local.init {
-                        self.hash_expr(init);
-                    }
+        std::mem::discriminant(&b.node).hash(&mut self.s);
+
+        match &b.node {
+            StmtKind::Local(local) => {
+                if let Some(ref init) = local.init {
+                    self.hash_expr(init);
                 }
             },
-            StmtKind::Expr(ref expr, _) => {
-                let c: fn(_, _) -> _ = StmtKind::Expr;
-                c.hash(&mut self.s);
+            StmtKind::Item(..) => {},
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
                 self.hash_expr(expr);
             },
-            StmtKind::Semi(ref expr, _) => {
-                let c: fn(_, _) -> _ = StmtKind::Semi;
-                c.hash(&mut self.s);
+        }
+    }
+
+    pub fn hash_guard(&mut self, g: &Guard) {
+        match g {
+            Guard::If(ref expr) => {
                 self.hash_expr(expr);
             },
         }
index b6c241a682533d9021cf6d6dbfd5ef73e4db5451..633ebb3dd4234e75fec70fd4ae77b842814a8da6 100644 (file)
@@ -1,54 +1,47 @@
-#![allow(print_stdout, use_debug)]
-
 //! checks for attributes
 
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::get_attr;
 use rustc::hir;
 use rustc::hir::print;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::session::Session;
+use rustc::{declare_lint_pass, declare_tool_lint};
 use syntax::ast::Attribute;
-use crate::utils::get_attr;
 
-/// **What it does:** Dumps every ast/hir node which has the `#[clippy_dump]`
-/// attribute
-///
-/// **Example:**
-/// ```rust
-/// #[clippy_dump]
-/// extern crate foo;
-/// ```
-///
-/// prints
-///
-/// ```
-/// item `foo`
-/// visibility inherited from outer item
-/// extern crate dylib source: "/path/to/foo.so"
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Dumps every ast/hir node which has the `#[clippy::dump]`
+    /// attribute
+    ///
+    /// **Example:**
+    /// ```rust
+    /// #[clippy::dump]
+    /// extern crate foo;
+    /// ```
+    ///
+    /// prints
+    ///
+    /// ```
+    /// item `foo`
+    /// visibility inherited from outer item
+    /// extern crate dylib source: "/path/to/foo.so"
+    /// ```
     pub DEEP_CODE_INSPECTION,
     internal_warn,
     "helper to dump info about code"
 }
 
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(DEEP_CODE_INSPECTION)
-    }
-}
+declare_lint_pass!(DeepCodeInspector => [DEEP_CODE_INSPECTION]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DeepCodeInspector {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
-        if !has_attr(&item.attrs) {
+        if !has_attr(cx.sess(), &item.attrs) {
             return;
         }
         print_item(cx, item);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) {
-        if !has_attr(&item.attrs) {
+        if !has_attr(cx.sess(), &item.attrs) {
             return;
         }
         println!("impl item `{}`", item.ident.name);
@@ -67,7 +60,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplI
         match item.node {
             hir::ImplItemKind::Const(_, body_id) => {
                 println!("associated constant");
-                print_expr(cx, &cx.tcx.hir.body(body_id).value, 1);
+                print_expr(cx, &cx.tcx.hir().body(body_id).value, 1);
             },
             hir::ImplItemKind::Method(..) => println!("method"),
             hir::ImplItemKind::Type(_) => println!("associated type"),
@@ -98,14 +91,14 @@ fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplI
     //
 
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        if !has_attr(&expr.attrs) {
+        if !has_attr(cx.sess(), &expr.attrs) {
             return;
         }
         print_expr(cx, expr, 0);
     }
 
     fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
-        if !has_attr(&arm.attrs) {
+        if !has_attr(cx.sess(), &arm.attrs) {
             return;
         }
         for pat in &arm.pats {
@@ -113,19 +106,28 @@ fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) {
         }
         if let Some(ref guard) = arm.guard {
             println!("guard:");
-            print_expr(cx, guard, 1);
+            print_guard(cx, guard, 1);
         }
         println!("body:");
         print_expr(cx, &arm.body, 1);
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
-        if !has_attr(stmt.node.attrs()) {
+        if !has_attr(cx.sess(), stmt.node.attrs()) {
             return;
         }
         match stmt.node {
-            hir::StmtKind::Decl(ref decl, _) => print_decl(cx, decl),
-            hir::StmtKind::Expr(ref e, _) | hir::StmtKind::Semi(ref e, _) => print_expr(cx, e, 0),
+            hir::StmtKind::Local(ref local) => {
+                println!("local variable of type {}", cx.tables.node_type(local.hir_id));
+                println!("pattern:");
+                print_pat(cx, &local.pat, 0);
+                if let Some(ref e) = local.init {
+                    println!("init expression:");
+                    print_expr(cx, e, 0);
+                }
+            },
+            hir::StmtKind::Item(_) => println!("item decl"),
+            hir::StmtKind::Expr(ref e) | hir::StmtKind::Semi(ref e) => print_expr(cx, e, 0),
         }
     }
     // fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx
@@ -137,25 +139,11 @@ fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
     //
 }
 
-fn has_attr(attrs: &[Attribute]) -> bool {
-    get_attr(attrs, "dump").count() > 0
-}
-
-fn print_decl(cx: &LateContext<'_, '_>, decl: &hir::Decl) {
-    match decl.node {
-        hir::DeclKind::Local(ref local) => {
-            println!("local variable of type {}", cx.tables.node_id_to_type(local.hir_id));
-            println!("pattern:");
-            print_pat(cx, &local.pat, 0);
-            if let Some(ref e) = local.init {
-                println!("init expression:");
-                print_expr(cx, e, 0);
-            }
-        },
-        hir::DeclKind::Item(_) => println!("item decl"),
-    }
+fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool {
+    get_attr(sess, attrs, "dump").count() > 0
 }
 
+#[allow(clippy::similar_names)]
 fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr, indent: usize) {
     let ind = "  ".repeat(indent);
     println!("{}+", ind);
@@ -221,15 +209,6 @@ fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr, indent: usize) {
             print_expr(cx, e, indent + 1);
             println!("{}target type: {:?}", ind, target);
         },
-        hir::ExprKind::If(ref e, _, ref els) => {
-            println!("{}If", ind);
-            println!("{}condition:", ind);
-            print_expr(cx, e, indent + 1);
-            if let Some(ref els) = *els {
-                println!("{}else:", ind);
-                print_expr(cx, els, indent + 1);
-            }
-        },
         hir::ExprKind::While(ref cond, _, _) => {
             println!("{}While", ind);
             println!("{}condition:", ind);
@@ -337,14 +316,21 @@ fn print_expr(cx: &LateContext<'_, '_>, expr: &hir::Expr, indent: usize) {
             println!("{}value:", ind);
             print_expr(cx, val, indent + 1);
             println!("{}repeat count:", ind);
-            print_expr(cx, &cx.tcx.hir.body(anon_const.body).value, indent + 1);
+            print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+        },
+        hir::ExprKind::Err => {
+            println!("{}Err", ind);
+        },
+        hir::ExprKind::DropTemps(ref e) => {
+            println!("{}DropTemps", ind);
+            print_expr(cx, e, indent + 1);
         },
     }
 }
 
 fn print_item(cx: &LateContext<'_, '_>, item: &hir::Item) {
-    let did = cx.tcx.hir.local_def_id(item.id);
-    println!("item `{}`", item.name);
+    let did = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
+    println!("item `{}`", item.ident.name);
     match item.vis.node {
         hir::VisibilityKind::Public => println!("public"),
         hir::VisibilityKind::Crate(_) => println!("visible crate wide"),
@@ -356,7 +342,7 @@ fn print_item(cx: &LateContext<'_, '_>, item: &hir::Item) {
     }
     match item.node {
         hir::ItemKind::ExternCrate(ref _renamed_from) => {
-            let def_id = cx.tcx.hir.local_def_id(item.id);
+            let def_id = cx.tcx.hir().local_def_id_from_hir_id(item.hir_id);
             if let Some(crate_id) = cx.tcx.extern_mod_stmt_cnum(def_id) {
                 let source = cx.tcx.used_crate_source(crate_id);
                 if let Some(ref src) = source.dylib {
@@ -404,7 +390,7 @@ fn print_item(cx: &LateContext<'_, '_>, item: &hir::Item) {
         },
         hir::ItemKind::TraitAlias(..) => {
             println!("trait alias");
-        }
+        },
         hir::ItemKind::Impl(_, _, _, _, Some(ref _trait_ref), _, _) => {
             println!("trait impl");
         },
@@ -414,12 +400,13 @@ fn print_item(cx: &LateContext<'_, '_>, item: &hir::Item) {
     }
 }
 
+#[allow(clippy::similar_names)]
 fn print_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat, indent: usize) {
     let ind = "  ".repeat(indent);
     println!("{}+", ind);
     match pat.node {
         hir::PatKind::Wild => println!("{}Wild", ind),
-        hir::PatKind::Binding(ref mode, _, ident, ref inner) => {
+        hir::PatKind::Binding(ref mode, .., ident, ref inner) => {
             println!("{}Binding", ind);
             println!("{}mode: {:?}", ind, mode);
             println!("{}name: {}", ind, ident.name);
@@ -515,3 +502,14 @@ fn print_pat(cx: &LateContext<'_, '_>, pat: &hir::Pat, indent: usize) {
         },
     }
 }
+
+fn print_guard(cx: &LateContext<'_, '_>, guard: &hir::Guard, indent: usize) {
+    let ind = "  ".repeat(indent);
+    println!("{}+", ind);
+    match guard {
+        hir::Guard::If(expr) => {
+            println!("{}If", ind);
+            print_expr(cx, expr, indent + 1);
+        },
+    }
+}
index 32aee09917717f48df24064b8028b263d03a8cc6..3ba2cd38c35fda1252ed3431d4987a8a68ab4704 100644 (file)
@@ -1,85 +1,88 @@
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
-use rustc::hir::*;
+use crate::utils::{match_def_path, match_type, paths, span_help_and_lint, span_lint, walk_ptrs_ty};
+use if_chain::if_chain;
 use rustc::hir;
+use rustc::hir::def::{DefKind, Res};
 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use crate::utils::{match_qpath, paths, span_lint};
-use syntax::symbol::LocalInternedString;
-use syntax::ast::{Crate as AstCrate, ItemKind, Name, NodeId};
-use syntax::codemap::Span;
-use std::collections::{HashMap, HashSet};
-
-
-/// **What it does:** Checks for various things we like to keep tidy in clippy.
-///
-/// **Why is this bad?** We like to pretend we're an example of tidy code.
-///
-/// **Known problems:** None.
-///
-/// **Example:** Wrong ordering of the util::paths constants.
+use rustc::hir::*;
+use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use syntax::ast::{Crate as AstCrate, Name};
+use syntax::source_map::Span;
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for various things we like to keep tidy in clippy.
+    ///
+    /// **Why is this bad?** We like to pretend we're an example of tidy code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:** Wrong ordering of the util::paths constants.
     pub CLIPPY_LINTS_INTERNAL,
     internal,
     "various things that will negatively affect your clippy experience"
 }
 
-
-/// **What it does:** Ensures every lint is associated to a `LintPass`.
-///
-/// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without
-/// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
-/// know the name of the lint.
-///
-/// **Known problems:** Only checks for lints associated using the `lint_array!`
-/// macro.
-///
-/// **Example:**
-/// ```rust
-/// declare_lint! { pub LINT_1, ... }
-/// declare_lint! { pub LINT_2, ... }
-/// declare_lint! { pub FORGOTTEN_LINT, ... }
-/// // ...
-/// pub struct Pass;
-/// impl LintPass for Pass {
-///     fn get_lints(&self) -> LintArray {
-///         lint_array![LINT_1, LINT_2]
-///         // missing FORGOTTEN_LINT
-///     }
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Ensures every lint is associated to a `LintPass`.
+    ///
+    /// **Why is this bad?** The compiler only knows lints via a `LintPass`. Without
+    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
+    /// know the name of the lint.
+    ///
+    /// **Known problems:** Only checks for lints associated using the
+    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// declare_lint! { pub LINT_1, ... }
+    /// declare_lint! { pub LINT_2, ... }
+    /// declare_lint! { pub FORGOTTEN_LINT, ... }
+    /// // ...
+    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
+    /// // missing FORGOTTEN_LINT
+    /// ```
     pub LINT_WITHOUT_LINT_PASS,
     internal,
     "declaring a lint without associating it in a LintPass"
 }
 
-
-#[derive(Copy, Clone)]
-pub struct Clippy;
-
-impl LintPass for Clippy {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(CLIPPY_LINTS_INTERNAL)
-    }
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
+    /// variant of the function.
+    ///
+    /// **Why is this bad?** The `utils::*` variants also add a link to the Clippy documentation to the
+    /// warning/error messages.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust
+    /// cx.span_lint(LINT_NAME, "message");
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// utils::span_lint(cx, LINT_NAME, "message");
+    /// ```
+    pub COMPILER_LINT_FUNCTIONS,
+    internal,
+    "usage of the lint functions of the compiler instead of the utils::* variant"
 }
 
-impl EarlyLintPass for Clippy {
-    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
-        if let Some(utils) = krate
-            .module
-            .items
-            .iter()
-            .find(|item| item.ident.name == "utils")
-        {
+declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
+
+impl EarlyLintPass for ClippyLintsInternal {
+    fn check_crate(&mut self, _cx: &EarlyContext<'_>, _krate: &AstCrate) {
+        /*
+        FIXME: turn back on when we get rid of all the lazy_statics
+        if let Some(utils) = krate.module.items.iter().find(|item| item.ident.name == *sym::utils) {
             if let ItemKind::Mod(ref utils_mod) = utils.node {
-                if let Some(paths) = utils_mod
-                    .items
-                    .iter()
-                    .find(|item| item.ident.name == "paths")
-                {
+                if let Some(paths) = utils_mod.items.iter().find(|item| item.ident.name == *sym::paths) {
                     if let ItemKind::Mod(ref paths_mod) = paths.node {
                         let mut last_name: Option<LocalInternedString> = None;
-                        for item in &paths_mod.items {
+                        for item in &*paths_mod.items {
                             let name = item.ident.as_str();
                             if let Some(ref last_name) = last_name {
                                 if **last_name > *name {
@@ -98,37 +101,42 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
                 }
             }
         }
+        */
     }
 }
 
-
-
 #[derive(Clone, Debug, Default)]
 pub struct LintWithoutLintPass {
-    declared_lints: HashMap<Name, Span>,
-    registered_lints: HashSet<Name>,
-}
-
-
-impl LintPass for LintWithoutLintPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(LINT_WITHOUT_LINT_PASS)
-    }
+    declared_lints: FxHashMap<Name, Span>,
+    registered_lints: FxHashSet<Name>,
 }
 
+impl_lint_pass!(LintWithoutLintPass => [LINT_WITHOUT_LINT_PASS]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LintWithoutLintPass {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
-        if let hir::ItemKind::Static(ref ty, MutImmutable, body_id) = item.node {
-            if is_lint_ref_type(ty) {
-                self.declared_lints.insert(item.name, item.span);
-            } else if is_lint_array_type(ty) && item.name == "ARRAY" {
-                if let VisibilityKind::Inherited = item.vis.node {
+        if let hir::ItemKind::Static(ref ty, MutImmutable, _) = item.node {
+            if is_lint_ref_type(cx, ty) {
+                self.declared_lints.insert(item.ident.name, item.span);
+            }
+        } else if let hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node {
+            if_chain! {
+                if let hir::TraitRef{path, ..} = trait_ref;
+                if let Res::Def(DefKind::Trait, def_id) = path.res;
+                if match_def_path(cx, def_id, &*paths::LINT_PASS);
+                then {
                     let mut collector = LintCollector {
                         output: &mut self.registered_lints,
                         cx,
                     };
-                    collector.visit_expr(&cx.tcx.hir.body(body_id).value);
+                    let body_id = cx.tcx.hir().body_owned_by(
+                        impl_item_refs
+                            .iter()
+                            .find(|iiref| iiref.ident.as_str() == "get_lints")
+                            .expect("LintPass needs to implement get_lints")
+                            .id.hir_id
+                    );
+                    collector.visit_expr(&cx.tcx.hir().body(body_id).value);
                 }
             }
         }
@@ -136,13 +144,13 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
 
     fn check_crate_post(&mut self, cx: &LateContext<'a, 'tcx>, _: &'tcx Crate) {
         for (lint_name, &lint_span) in &self.declared_lints {
-            // When using the `declare_lint!` macro, the original `lint_span`'s
+            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
             // file points to "<rustc macros>".
             // `compiletest-rs` thinks that's an error in a different file and
             // just ignores it. This causes the test in compile-fail/lint_pass
             // not able to capture the error.
             // Therefore, we need to climb the macro expansion tree and find the
-            // actual span that invoked `declare_lint!`:
+            // actual span that invoked `declare_tool_lint!`:
             let lint_span = lint_span
                 .ctxt()
                 .outer()
@@ -162,8 +170,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'a, 'tcx>, _: &'tcx Crate) {
     }
 }
 
-
-fn is_lint_ref_type(ty: &Ty) -> bool {
+fn is_lint_ref_type<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &Ty) -> bool {
     if let TyKind::Rptr(
         _,
         MutTy {
@@ -173,23 +180,17 @@ fn is_lint_ref_type(ty: &Ty) -> bool {
     ) = ty.node
     {
         if let TyKind::Path(ref path) = inner.node {
-            return match_qpath(path, &paths::LINT);
+            if let Res::Def(DefKind::Struct, def_id) = cx.tables.qpath_res(path, inner.hir_id) {
+                return match_def_path(cx, def_id, &*paths::LINT);
+            }
         }
     }
-    false
-}
 
-
-fn is_lint_array_type(ty: &Ty) -> bool {
-    if let TyKind::Path(ref path) = ty.node {
-        match_qpath(path, &paths::LINT_ARRAY)
-    } else {
-        false
-    }
+    false
 }
 
 struct LintCollector<'a, 'tcx: 'a> {
-    output: &'a mut HashSet<Name>,
+    output: &'a mut FxHashSet<Name>,
     cx: &'a LateContext<'a, 'tcx>,
 }
 
@@ -198,12 +199,53 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         walk_expr(self, expr);
     }
 
-    fn visit_path(&mut self, path: &'tcx Path, _: NodeId) {
+    fn visit_path(&mut self, path: &'tcx Path, _: HirId) {
         if path.segments.len() == 1 {
             self.output.insert(path.segments[0].ident.name);
         }
     }
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::All(&self.cx.tcx.hir)
+        NestedVisitorMap::All(&self.cx.tcx.hir())
+    }
+}
+
+#[derive(Clone, Default)]
+pub struct CompilerLintFunctions {
+    map: FxHashMap<String, String>,
+}
+
+impl CompilerLintFunctions {
+    pub fn new() -> Self {
+        let mut map = FxHashMap::default();
+        map.insert("span_lint".to_string(), "utils::span_lint".to_string());
+        map.insert("struct_span_lint".to_string(), "utils::span_lint".to_string());
+        map.insert("lint".to_string(), "utils::span_lint".to_string());
+        map.insert("span_lint_note".to_string(), "utils::span_note_and_lint".to_string());
+        map.insert("span_lint_help".to_string(), "utils::span_help_and_lint".to_string());
+        Self { map }
+    }
+}
+
+impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CompilerLintFunctions {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
+        if_chain! {
+            if let ExprKind::MethodCall(ref path, _, ref args) = expr.node;
+            let fn_name = path.ident.as_str().to_string();
+            if let Some(sugg) = self.map.get(&fn_name);
+            let ty = walk_ptrs_ty(cx.tables.expr_ty(&args[0]));
+            if match_type(cx, ty, &*paths::EARLY_CONTEXT)
+                || match_type(cx, ty, &*paths::LATE_CONTEXT);
+            then {
+                span_help_and_lint(
+                    cx,
+                    COMPILER_LINT_FUNCTIONS,
+                    path.ident.span,
+                    "usage of a compiler lint function",
+                    &format!("please use the Clippy variant of this function: `{}`", sugg),
+                );
+            }
+        }
     }
 }
index 0b2103ca7eaa505ab71a1ebe88189fe6252b4c95..e08a83dd54c158c2021a48218dccc1919562b60e 100644 (file)
-use crate::reexport::*;
-use matches::matches;
-use if_chain::if_chain;
-use rustc::hir;
-use rustc::hir::*;
-use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
-use rustc::hir::def::Def;
-use rustc::hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc::hir::map::Node;
-use rustc::lint::{LateContext, Level, Lint, LintContext};
-use rustc::session::Session;
-use rustc::traits;
-use rustc::ty::{self, Binder, Ty, TyCtxt, layout::{self, IntegerExt}, subst::Kind};
-use rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart};
-use std::borrow::Cow;
-use std::env;
-use std::mem;
-use std::str::FromStr;
-use std::rc::Rc;
-use syntax::ast::{self, LitKind};
-use syntax::attr;
-use syntax::codemap::{CompilerDesugaringKind, ExpnFormat, Span, DUMMY_SP};
-use syntax::errors::DiagnosticBuilder;
-use syntax::ptr::P;
-use syntax::symbol::keywords;
-
+pub mod attrs;
+pub mod author;
+pub mod camel_case;
 pub mod comparisons;
 pub mod conf;
 pub mod constants;
+mod diagnostics;
+pub mod higher;
 mod hir_utils;
-pub mod paths;
-pub mod sugg;
 pub mod inspector;
 pub mod internal_lints;
-pub mod author;
+pub mod paths;
 pub mod ptr;
+pub mod sugg;
+pub mod sym;
 pub mod usage;
+pub use self::attrs::*;
+pub use self::diagnostics::*;
 pub use self::hir_utils::{SpanlessEq, SpanlessHash};
 
-pub type MethodArgs = HirVec<P<Expr>>;
+use std::borrow::Cow;
+use std::mem;
 
-pub mod higher;
+use if_chain::if_chain;
+use matches::matches;
+use rustc::hir;
+use rustc::hir::def::{DefKind, Res};
+use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc::hir::intravisit::{NestedVisitorMap, Visitor};
+use rustc::hir::Node;
+use rustc::hir::*;
+use rustc::lint::{LateContext, Level, Lint, LintContext};
+use rustc::traits;
+use rustc::ty::{
+    self,
+    layout::{self, IntegerExt},
+    subst::Kind,
+    Binder, Ty, TyCtxt,
+};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::Applicability;
+use syntax::ast::{self, LitKind};
+use syntax::attr;
+use syntax::ext::hygiene::ExpnFormat;
+use syntax::source_map::{Span, DUMMY_SP};
+use syntax::symbol::{keywords, Symbol};
+
+use crate::reexport::*;
 
-/// Returns true if the two spans come from differing expansions (i.e. one is
-/// from a macro and one
-/// isn't).
+/// Returns `true` if the two spans come from differing expansions (i.e., one is
+/// from a macro and one isn't).
 pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
     rhs.ctxt() != lhs.ctxt()
 }
 
-pub fn in_constant(cx: &LateContext<'_, '_>, id: NodeId) -> bool {
-    let parent_id = cx.tcx.hir.get_parent(id);
-    match cx.tcx.hir.body_owner_kind(parent_id) {
-        hir::BodyOwnerKind::Fn => false,
-        hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(..) => true,
+/// Returns `true` if the given `NodeId` is inside a constant context
+///
+/// # Example
+///
+/// ```rust,ignore
+/// if in_constant(cx, expr.id) {
+///     // Do something
+/// }
+/// ```
+pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool {
+    let parent_id = cx.tcx.hir().get_parent_item(id);
+    match cx.tcx.hir().get_by_hir_id(parent_id) {
+        Node::Item(&Item {
+            node: ItemKind::Const(..),
+            ..
+        })
+        | Node::TraitItem(&TraitItem {
+            node: TraitItemKind::Const(..),
+            ..
+        })
+        | Node::ImplItem(&ImplItem {
+            node: ImplItemKind::Const(..),
+            ..
+        })
+        | Node::AnonConst(_)
+        | Node::Item(&Item {
+            node: ItemKind::Static(..),
+            ..
+        }) => true,
+        Node::Item(&Item {
+            node: ItemKind::Fn(_, header, ..),
+            ..
+        }) => header.constness == Constness::Const,
+        _ => false,
     }
 }
 
-/// Returns true if this `expn_info` was expanded by any macro.
-pub fn in_macro(span: Span) -> bool {
-    span.ctxt().outer().expn_info().map_or(false, |info| {
-        match info.format {
-            // don't treat range expressions desugared to structs as "in_macro"
-            ExpnFormat::CompilerDesugaring(kind) => kind != CompilerDesugaringKind::DotFill,
-            _ => true,
-        }
-    })
+/// Returns `true` if this `expn_info` was expanded by any macro or desugaring
+pub fn in_macro_or_desugar(span: Span) -> bool {
+    span.ctxt().outer().expn_info().is_some()
 }
 
-/// Returns true if `expn_info` was expanded by range expressions.
-pub fn is_range_expression(span: Span) -> bool {
-    span.ctxt().outer().expn_info().map_or(false, |info| {
-        match info.format {
-            ExpnFormat::CompilerDesugaring(CompilerDesugaringKind::DotFill) => true,
-            _ => false,
+/// Returns `true` if this `expn_info` was expanded by any macro.
+pub fn in_macro(span: Span) -> bool {
+    if let Some(info) = span.ctxt().outer().expn_info() {
+        if let ExpnFormat::CompilerDesugaring(..) = info.format {
+            false
+        } else {
+            true
         }
-    })
-}
-
-/// Check if a `DefId`'s path matches the given absolute type path usage.
-///
-/// # Examples
-/// ```rust,ignore
-/// match_def_path(cx.tcx, id, &["core", "option", "Option"])
-/// ```
-///
-/// See also the `paths` module.
-pub fn match_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, path: &[&str]) -> bool {
-    use syntax::symbol;
-
-    struct AbsolutePathBuffer {
-        names: Vec<symbol::LocalInternedString>,
+    } else {
+        false
     }
-
-    impl ty::item_path::ItemPathBuffer for AbsolutePathBuffer {
-        fn root_mode(&self) -> &ty::item_path::RootMode {
-            const ABSOLUTE: &ty::item_path::RootMode = &ty::item_path::RootMode::Absolute;
-            ABSOLUTE
-        }
-
-        fn push(&mut self, text: &str) {
-            self.names.push(symbol::Symbol::intern(text).as_str());
+}
+// If the snippet is empty, it's an attribute that was inserted during macro
+// expansion and we want to ignore those, because they could come from external
+// sources that the user has no control over.
+// For some reason these attributes don't have any expansion info on them, so
+// we have to check it this way until there is a better way.
+pub fn is_present_in_source<'a, T: LintContext<'a>>(cx: &T, span: Span) -> bool {
+    if let Some(snippet) = snippet_opt(cx, span) {
+        if snippet.is_empty() {
+            return false;
         }
     }
-
-    let mut apb = AbsolutePathBuffer { names: vec![] };
-
-    tcx.push_item_path(&mut apb, def_id);
-
-    apb.names.len() == path.len()
-        && apb.names
-            .into_iter()
-            .zip(path.iter())
-            .all(|(a, &b)| *a == *b)
+    true
 }
 
-/// Check if type is struct, enum or union type with given def path.
-pub fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool {
+/// Checks if type is struct, enum or union type with the given def path.
+pub fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[Symbol]) -> bool {
     match ty.sty {
-        ty::TyAdt(adt, _) => match_def_path(cx.tcx, adt.did, path),
+        ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
         _ => false,
     }
 }
 
-/// Check if the method call given in `expr` belongs to given type.
-pub fn match_impl_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[&str]) -> bool {
-    let method_call = cx.tables.type_dependent_defs()[expr.hir_id];
-    let trt_id = cx.tcx.impl_of_method(method_call.def_id());
-    if let Some(trt_id) = trt_id {
-        match_def_path(cx.tcx, trt_id, path)
-    } else {
-        false
-    }
-}
-
-/// Check if the method call given in `expr` belongs to given trait.
-pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[&str]) -> bool {
-    let method_call = cx.tables.type_dependent_defs()[expr.hir_id];
-    let trt_id = cx.tcx.trait_of_item(method_call.def_id());
+/// Checks if the method call given in `expr` belongs to the given trait.
+pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr, path: &[Symbol]) -> bool {
+    let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap();
+    let trt_id = cx.tcx.trait_of_item(def_id);
     if let Some(trt_id) = trt_id {
-        match_def_path(cx.tcx, trt_id, path)
+        match_def_path(cx, trt_id, path)
     } else {
         false
     }
 }
 
-/// Check if an expression references a variable of the given name.
+/// Checks if an expression references a variable of the given name.
 pub fn match_var(expr: &Expr, var: Name) -> bool {
     if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.node {
         if path.segments.len() == 1 && path.segments[0].ident.name == var {
@@ -154,12 +150,9 @@ pub fn match_var(expr: &Expr, var: Name) -> bool {
     false
 }
 
-
 pub fn last_path_segment(path: &QPath) -> &PathSegment {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments
-            .last()
-            .expect("A path must have at least one segment"),
+        QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
         QPath::TypeRelative(_, ref seg) => seg,
     }
 }
@@ -172,18 +165,22 @@ pub fn single_segment_path(path: &QPath) -> Option<&PathSegment> {
     }
 }
 
-/// Match a `Path` against a slice of segment string literals.
+/// Matches a `QPath` against a slice of segment string literals.
+///
+/// There is also `match_path` if you are dealing with a `rustc::hir::Path` instead of a
+/// `rustc::hir::QPath`.
 ///
 /// # Examples
 /// ```rust,ignore
 /// match_qpath(path, &["std", "rt", "begin_unwind"])
 /// ```
-pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool {
+pub fn match_qpath(path: &QPath, segments: &[Symbol]) -> bool {
     match *path {
         QPath::Resolved(_, ref path) => match_path(path, segments),
         QPath::TypeRelative(ref ty, ref segment) => match ty.node {
             TyKind::Path(ref inner_path) => {
-                !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)])
+                !segments.is_empty()
+                    && match_qpath(inner_path, &segments[..(segments.len() - 1)])
                     && segment.ident.name == segments[segments.len() - 1]
             },
             _ => false,
@@ -191,7 +188,23 @@ pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool {
     }
 }
 
-pub fn match_path(path: &Path, segments: &[&str]) -> bool {
+/// Matches a `Path` against a slice of segment string literals.
+///
+/// There is also `match_qpath` if you are dealing with a `rustc::hir::QPath` instead of a
+/// `rustc::hir::Path`.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// if match_path(&trait_ref.path, &*paths::HASH) {
+///     // This is the `std::hash::Hash` trait.
+/// }
+///
+/// if match_path(ty_path, &["rustc", "lint", "Lint"]) {
+///     // This is a `rustc::lint::Lint`.
+/// }
+/// ```
+pub fn match_path(path: &Path, segments: &[Symbol]) -> bool {
     path.segments
         .iter()
         .rev()
@@ -199,13 +212,13 @@ pub fn match_path(path: &Path, segments: &[&str]) -> bool {
         .all(|(a, b)| a.ident.name == *b)
 }
 
-/// Match a `Path` against a slice of segment string literals, e.g.
+/// Matches a `Path` against a slice of segment string literals, e.g.
 ///
 /// # Examples
 /// ```rust,ignore
 /// match_qpath(path, &["std", "rt", "begin_unwind"])
 /// ```
-pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
+pub fn match_path_ast(path: &ast::Path, segments: &[Symbol]) -> bool {
     path.segments
         .iter()
         .rev()
@@ -213,12 +226,10 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
         .all(|(a, b)| a.ident.name == *b)
 }
 
-/// Get the definition associated to a path.
-pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def> {
+/// Gets the definition associated to a path.
+pub fn path_to_res(cx: &LateContext<'_, '_>, path: &[Symbol]) -> Option<(def::Res)> {
     let crates = cx.tcx.crates();
-    let krate = crates
-        .iter()
-        .find(|&&krate| cx.tcx.crate_name(krate) == path[0]);
+    let krate = crates.iter().find(|&&krate| cx.tcx.crate_name(krate) == path[0]);
     if let Some(krate) = krate {
         let krate = DefId {
             krate: *krate,
@@ -233,13 +244,13 @@ pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def>
                 None => return None,
             };
 
-            for item in mem::replace(&mut items, Rc::new(vec![])).iter() {
+            for item in mem::replace(&mut items, Lrc::new(vec![])).iter() {
                 if item.ident.name == *segment {
                     if path_it.peek().is_none() {
-                        return Some(item.def);
+                        return Some(item.res);
                     }
 
-                    items = cx.tcx.item_children(item.def.def_id());
+                    items = cx.tcx.item_children(item.res.def_id());
                     break;
                 }
             }
@@ -250,19 +261,19 @@ pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def>
 }
 
 /// Convenience function to get the `DefId` of a trait by path.
-pub fn get_trait_def_id(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<DefId> {
-    let def = match path_to_def(cx, path) {
-        Some(def) => def,
+pub fn get_trait_def_id(cx: &LateContext<'_, '_>, path: &[Symbol]) -> Option<DefId> {
+    let res = match path_to_res(cx, path) {
+        Some(res) => res,
         None => return None,
     };
 
-    match def {
-        def::Def::Trait(trait_id) => Some(trait_id),
+    match res {
+        def::Res::Def(DefKind::Trait, trait_id) => Some(trait_id),
         _ => None,
     }
 }
 
-/// Check whether a type implements a trait.
+/// Checks whether a type implements a trait.
 /// See also `get_trait_def_id`.
 pub fn implements_trait<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
@@ -271,40 +282,96 @@ pub fn implements_trait<'a, 'tcx>(
     ty_params: &[Kind<'tcx>],
 ) -> bool {
     let ty = cx.tcx.erase_regions(&ty);
-    let obligation =
-        cx.tcx
-            .predicate_for_trait_def(cx.param_env, traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params);
-    cx.tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold(&obligation))
+    let obligation = cx.tcx.predicate_for_trait_def(
+        cx.param_env,
+        traits::ObligationCause::dummy(),
+        trait_id,
+        0,
+        ty,
+        ty_params,
+    );
+    cx.tcx
+        .infer_ctxt()
+        .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+}
+
+/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
+///
+/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
+///
+/// ```rust
+/// struct Point(isize, isize);
+///
+/// impl std::ops::Add for Point {
+///     type Output = Self;
+///
+///     fn add(self, other: Self) -> Self {
+///         Point(0, 0)
+///     }
+/// }
+/// ```
+pub fn trait_ref_of_method(cx: &LateContext<'_, '_>, hir_id: HirId) -> Option<TraitRef> {
+    // Get the implemented trait for the current function
+    let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
+    if_chain! {
+        if parent_impl != hir::CRATE_HIR_ID;
+        if let hir::Node::Item(item) = cx.tcx.hir().get_by_hir_id(parent_impl);
+        if let hir::ItemKind::Impl(_, _, _, _, trait_ref, _, _) = &item.node;
+        then { return trait_ref.clone(); }
+    }
+    None
 }
 
-/// Check whether this type implements Drop.
-pub fn has_drop(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
-    let struct_ty = cx.tables.expr_ty(expr);
-    match struct_ty.ty_adt_def() {
+/// Checks whether this type implements `Drop`.
+pub fn has_drop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
+    match ty.ty_adt_def() {
         Some(def) => def.has_dtor(cx.tcx),
         _ => false,
     }
 }
 
-/// Resolve the definition of a node from its `HirId`.
-pub fn resolve_node(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> def::Def {
-    cx.tables.qpath_def(qpath, id)
+/// Resolves the definition of a node from its `HirId`.
+pub fn resolve_node(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> Res {
+    cx.tables.qpath_res(qpath, id)
+}
+
+/// Returns the method names and argument list of nested method call expressions that make up
+/// `expr`.
+pub fn method_calls<'a>(expr: &'a Expr, max_depth: usize) -> (Vec<Symbol>, Vec<&'a [Expr]>) {
+    let mut method_names = Vec::with_capacity(max_depth);
+    let mut arg_lists = Vec::with_capacity(max_depth);
+
+    let mut current = expr;
+    for _ in 0..max_depth {
+        if let ExprKind::MethodCall(path, _, args) = &current.node {
+            if args.iter().any(|e| in_macro_or_desugar(e.span)) {
+                break;
+            }
+            method_names.push(path.ident.name);
+            arg_lists.push(&**args);
+            current = &args[0];
+        } else {
+            break;
+        }
+    }
+
+    (method_names, arg_lists)
 }
 
-/// Match an `Expr` against a chain of methods, and return the matched `Expr`s.
+/// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
 ///
 /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
 /// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec`
 /// containing the `Expr`s for
 /// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a [Expr]>> {
+pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[Symbol]) -> Option<Vec<&'a [Expr]>> {
     let mut current = expr;
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
         if let ExprKind::MethodCall(ref path, _, ref args) = current.node {
             if path.ident.name == *method_name {
-                if args.iter().any(|e| in_macro(e.span)) {
+                if args.iter().any(|e| in_macro_or_desugar(e.span)) {
                     return None;
                 }
                 matched.push(&**args); // build up `matched` backwards
@@ -316,26 +383,35 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a
             return None;
         }
     }
-    matched.reverse(); // reverse `matched`, so that it is in the same order as `methods`
+    // Reverse `matched` so that it is in the same order as `methods`.
+    matched.reverse();
     Some(matched)
 }
 
+/// Returns `true` if the provided `def_id` is an entrypoint to a program.
+pub fn is_entrypoint_fn(cx: &LateContext<'_, '_>, def_id: DefId) -> bool {
+    if let Some((entry_fn_def_id, _)) = cx.tcx.entry_fn(LOCAL_CRATE) {
+        return def_id == entry_fn_def_id;
+    }
+    false
+}
 
-/// Get the name of the item the expression is in, if available.
+/// Gets the name of the item the expression is in, if available.
 pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Name> {
-    let parent_id = cx.tcx.hir.get_parent(expr.id);
-    match cx.tcx.hir.find(parent_id) {
-        Some(Node::NodeItem(&Item { ref name, .. })) => Some(*name),
-        Some(Node::NodeTraitItem(&TraitItem { ident, .. })) |
-        Some(Node::NodeImplItem(&ImplItem { ident, .. })) => Some(ident.name),
+    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
+    match cx.tcx.hir().find_by_hir_id(parent_id) {
+        Some(Node::Item(&Item { ref ident, .. })) => Some(ident.name),
+        Some(Node::TraitItem(&TraitItem { ident, .. })) | Some(Node::ImplItem(&ImplItem { ident, .. })) => {
+            Some(ident.name)
+        },
         _ => None,
     }
 }
 
-/// Get the name of a `Pat`, if any
+/// Gets the name of a `Pat`, if any.
 pub fn get_pat_name(pat: &Pat) -> Option<Name> {
     match pat.node {
-        PatKind::Binding(_, _, ref spname, _) => Some(spname.name),
+        PatKind::Binding(.., ref spname, _) => Some(spname.name),
         PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
         PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
         _ => None,
@@ -358,18 +434,17 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 }
 
-/// check if an `Expr` contains a certain name
+/// Checks if an `Expr` contains a certain name.
 pub fn contains_name(name: Name, expr: &Expr) -> bool {
-    let mut cn = ContainsName {
-        name,
-        result: false,
-    };
+    let mut cn = ContainsName { name, result: false };
     cn.visit_expr(expr);
     cn.result
 }
 
-
-/// Convert a span to a code snippet if available, otherwise use default.
+/// Converts a span to a code snippet if available, otherwise use default.
+///
+/// This is useful if you want to provide suggestions for your lint or more generally, if you want
+/// to convert a given `Span` to a `str`.
 ///
 /// # Example
 /// ```rust,ignore
@@ -379,12 +454,44 @@ pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str)
     snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
 }
 
-/// Convert a span to a code snippet. Returns `None` if not available.
+/// Same as `snippet`, but it adapts the applicability level by following rules:
+///
+/// - Applicability level `Unspecified` will never be changed.
+/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
+/// - If the default value is used and the applicability level is `MachineApplicable`, change it to
+/// `HasPlaceholders`
+pub fn snippet_with_applicability<'a, 'b, T: LintContext<'b>>(
+    cx: &T,
+    span: Span,
+    default: &'a str,
+    applicability: &mut Applicability,
+) -> Cow<'a, str> {
+    if *applicability != Applicability::Unspecified && in_macro_or_desugar(span) {
+        *applicability = Applicability::MaybeIncorrect;
+    }
+    snippet_opt(cx, span).map_or_else(
+        || {
+            if *applicability == Applicability::MachineApplicable {
+                *applicability = Applicability::HasPlaceholders;
+            }
+            Cow::Borrowed(default)
+        },
+        From::from,
+    )
+}
+
+/// Same as `snippet`, but should only be used when it's clear that the input span is
+/// not a macro argument.
+pub fn snippet_with_macro_callsite<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
+    snippet(cx, span.source_callsite(), default)
+}
+
+/// Converts a span to a code snippet. Returns `None` if not available.
 pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> {
-    cx.sess().codemap().span_to_snippet(span).ok()
+    cx.sess().source_map().span_to_snippet(span).ok()
 }
 
-/// Convert a span (from a block) to a code snippet if available, otherwise use
+/// Converts a span (from a block) to a code snippet if available, otherwise use
 /// default.
 /// This trims the code of indentation, except for the first line. Use it for
 /// blocks or block-like
@@ -392,18 +499,30 @@ pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String>
 ///
 /// # Example
 /// ```rust,ignore
-/// snippet(cx, expr.span, "..")
+/// snippet_block(cx, expr.span, "..")
 /// ```
 pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
     let snip = snippet(cx, span, default);
     trim_multiline(snip, true)
 }
 
+/// Same as `snippet_block`, but adapts the applicability level by the rules of
+/// `snippet_with_applicabiliy`.
+pub fn snippet_block_with_applicability<'a, 'b, T: LintContext<'b>>(
+    cx: &T,
+    span: Span,
+    default: &'a str,
+    applicability: &mut Applicability,
+) -> Cow<'a, str> {
+    let snip = snippet_with_applicability(cx, span, default, applicability);
+    trim_multiline(snip, true)
+}
+
 /// Returns a new Span that covers the full last line of the given Span
 pub fn last_line_of_span<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Span {
-    let file_map_and_line = cx.sess().codemap().lookup_line(span.lo()).unwrap();
-    let line_no = file_map_and_line.line;
-    let line_start = &file_map_and_line.fm.lines[line_no];
+    let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
+    let line_no = source_map_and_line.line;
+    let line_start = &source_map_and_line.sf.lines[line_no];
     Span::new(*line_start, span.hi(), span.ctxt())
 }
 
@@ -417,7 +536,9 @@ pub fn expr_block<'a, 'b, T: LintContext<'b>>(
 ) -> Cow<'a, str> {
     let code = snippet_block(cx, expr.span, default);
     let string = option.unwrap_or_default();
-    if let ExprKind::Block(_, _) = expr.node {
+    if in_macro_or_desugar(expr.span) {
+        Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
+    } else if let ExprKind::Block(_, _) = expr.node {
         Cow::Owned(format!("{}{}", code, string))
     } else if string.is_empty() {
         Cow::Owned(format!("{{ {} }}", code))
@@ -435,19 +556,15 @@ pub fn trim_multiline(s: Cow<'_, str>, ignore_first: bool) -> Cow<'_, str> {
 }
 
 fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_, str> {
-    let x = s.lines()
+    let x = s
+        .lines()
         .skip(ignore_first as usize)
         .filter_map(|l| {
             if l.is_empty() {
                 None
             } else {
                 // ignore empty lines
-                Some(
-                    l.char_indices()
-                        .find(|&(_, x)| x != ch)
-                        .unwrap_or((l.len(), ch))
-                        .0,
-                )
+                Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0)
             }
         })
         .min()
@@ -471,16 +588,16 @@ fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_
     }
 }
 
-/// Get a parent expressions if any – this is useful to constrain a lint.
+/// Gets the parent expression, if any –- this is useful to constrain a lint.
 pub fn get_parent_expr<'c>(cx: &'c LateContext<'_, '_>, e: &Expr) -> Option<&'c Expr> {
-    let map = &cx.tcx.hir;
-    let node_id: NodeId = e.id;
-    let parent_id: NodeId = map.get_parent_node(node_id);
-    if node_id == parent_id {
+    let map = &cx.tcx.hir();
+    let hir_id = e.hir_id;
+    let parent_id = map.get_parent_node_by_hir_id(hir_id);
+    if hir_id == parent_id {
         return None;
     }
-    map.find(parent_id).and_then(|node| {
-        if let Node::NodeExpr(parent) = node {
+    map.find_by_hir_id(parent_id).and_then(|node| {
+        if let Node::Expr(parent) = node {
             Some(parent)
         } else {
             None
@@ -488,20 +605,22 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext<'_, '_>, e: &Expr) -> Option<&'c
     })
 }
 
-pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> {
-    let map = &cx.tcx.hir;
-    let enclosing_node = map.get_enclosing_scope(node)
-        .and_then(|enclosing_id| map.find(enclosing_id));
+pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, hir_id: HirId) -> Option<&'tcx Block> {
+    let map = &cx.tcx.hir();
+    let enclosing_node = map
+        .get_enclosing_scope(hir_id)
+        .and_then(|enclosing_id| map.find_by_hir_id(enclosing_id));
     if let Some(node) = enclosing_node {
         match node {
-            Node::NodeBlock(block) => Some(block),
-            Node::NodeItem(&Item {
+            Node::Block(block) => Some(block),
+            Node::Item(&Item {
                 node: ItemKind::Fn(_, _, _, eid),
                 ..
-            }) | Node::NodeImplItem(&ImplItem {
+            })
+            | Node::ImplItem(&ImplItem {
                 node: ImplItemKind::Method(_, eid),
                 ..
-            }) => match cx.tcx.hir.body(eid).value.node {
+            }) => match cx.tcx.hir().body(eid).value.node {
                 ExprKind::Block(ref block, _) => Some(block),
                 _ => None,
             },
@@ -512,131 +631,7 @@ pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeI
     }
 }
 
-pub struct DiagnosticWrapper<'a>(pub DiagnosticBuilder<'a>);
-
-impl<'a> Drop for DiagnosticWrapper<'a> {
-    fn drop(&mut self) {
-        self.0.emit();
-    }
-}
-
-impl<'a> DiagnosticWrapper<'a> {
-    fn docs_link(&mut self, lint: &'static Lint) {
-        if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
-            self.0.help(&format!(
-                "for further information visit https://rust-lang-nursery.github.io/rust-clippy/v{}/index.html#{}",
-                env!("CARGO_PKG_VERSION"),
-                lint.name_lower()
-            ));
-        }
-    }
-}
-
-pub fn span_lint<'a, T: LintContext<'a>>(cx: &T, lint: &'static Lint, sp: Span, msg: &str) {
-    DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg)).docs_link(lint);
-}
-
-pub fn span_help_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
-    cx: &'a T,
-    lint: &'static Lint,
-    span: Span,
-    msg: &str,
-    help: &str,
-) {
-    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
-    db.0.help(help);
-    db.docs_link(lint);
-}
-
-pub fn span_note_and_lint<'a, 'tcx: 'a, T: LintContext<'tcx>>(
-    cx: &'a T,
-    lint: &'static Lint,
-    span: Span,
-    msg: &str,
-    note_span: Span,
-    note: &str,
-) {
-    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, span, msg));
-    if note_span == span {
-        db.0.note(note);
-    } else {
-        db.0.span_note(note_span, note);
-    }
-    db.docs_link(lint);
-}
-
-pub fn span_lint_and_then<'a, 'tcx: 'a, T: LintContext<'tcx>, F>(
-    cx: &'a T,
-    lint: &'static Lint,
-    sp: Span,
-    msg: &str,
-    f: F,
-) where
-    F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
-{
-    let mut db = DiagnosticWrapper(cx.struct_span_lint(lint, sp, msg));
-    f(&mut db.0);
-    db.docs_link(lint);
-}
-
-/// Add a span lint with a suggestion on how to fix it.
-///
-/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
-/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x > 2)"`.
-///
-/// ```ignore
-/// error: This `.fold` can be more succinctly expressed as `.any`
-/// --> $DIR/methods.rs:390:13
-///     |
-/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
-///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
-///     |
-///     = note: `-D fold-any` implied by `-D warnings`
-/// ```
-pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>(
-    cx: &'a T,
-    lint: &'static Lint,
-    sp: Span,
-    msg: &str,
-    help: &str,
-    sugg: String,
-) {
-    span_lint_and_then(cx, lint, sp, msg, |db| {
-        db.span_suggestion(sp, help, sugg);
-    });
-}
-
-/// Create a suggestion made from several `span → replacement`.
-///
-/// Note: in the JSON format (used by `compiletest_rs`), the help message will
-/// appear once per
-/// replacement. In human-readable format though, it only appears once before
-/// the whole suggestion.
-pub fn multispan_sugg<I>(db: &mut DiagnosticBuilder<'_>, help_msg: String, sugg: I)
-where
-    I: IntoIterator<Item = (Span, String)>,
-{
-    let sugg = CodeSuggestion {
-        substitutions: vec![
-            Substitution {
-                parts: sugg.into_iter()
-                    .map(|(span, snippet)| {
-                        SubstitutionPart {
-                            snippet,
-                            span,
-                        }
-                    })
-                    .collect(),
-            }
-        ],
-        msg: help_msg,
-        show_code_when_inline: true,
-        applicability: Applicability::Unspecified,
-    };
-    db.suggestions.push(sugg);
-}
-
-/// Return the base type for HIR references and pointers.
+/// Returns the base type for HIR references and pointers.
 pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty {
     match ty.node {
         TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
@@ -644,27 +639,27 @@ pub fn walk_ptrs_hir_ty(ty: &hir::Ty) -> &hir::Ty {
     }
 }
 
-/// Return the base type for references and raw pointers.
+/// Returns the base type for references and raw pointers.
 pub fn walk_ptrs_ty(ty: Ty<'_>) -> Ty<'_> {
     match ty.sty {
-        ty::TyRef(_, ty, _) => walk_ptrs_ty(ty),
+        ty::Ref(_, ty, _) => walk_ptrs_ty(ty),
         _ => ty,
     }
 }
 
-/// Return the base type for references and raw pointers, and count reference
+/// Returns the base type for references and raw pointers, and count reference
 /// depth.
 pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
     fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
         match ty.sty {
-            ty::TyRef(_, ty, _) => inner(ty, depth + 1),
+            ty::Ref(_, ty, _) => inner(ty, depth + 1),
             _ => (ty, depth),
         }
     }
     inner(ty, 0)
 }
 
-/// Check whether the given expression is a constant literal of the given value.
+/// Checks whether the given expression is a constant literal of the given value.
 pub fn is_integer_literal(expr: &Expr, value: u128) -> bool {
     // FIXME: use constant folding
     if let ExprKind::Lit(ref spanned) = expr.node {
@@ -675,69 +670,24 @@ pub fn is_integer_literal(expr: &Expr, value: u128) -> bool {
     false
 }
 
+/// Returns `true` if the given `Expr` has been coerced before.
+///
+/// Examples of coercions can be found in the Nomicon at
+/// <https://doc.rust-lang.org/nomicon/coercions.html>.
+///
+/// See `rustc::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
+/// information on adjustments and coercions.
 pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
     cx.tables.adjustments().get(e.hir_id).is_some()
 }
 
-pub struct LimitStack {
-    stack: Vec<u64>,
-}
-
-impl Drop for LimitStack {
-    fn drop(&mut self) {
-        assert_eq!(self.stack.len(), 1);
-    }
-}
-
-impl LimitStack {
-    pub fn new(limit: u64) -> Self {
-        Self { stack: vec![limit] }
-    }
-    pub fn limit(&self) -> u64 {
-        *self.stack
-            .last()
-            .expect("there should always be a value in the stack")
-    }
-    pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
-        let stack = &mut self.stack;
-        parse_attrs(sess, attrs, name, |val| stack.push(val));
-    }
-    pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
-        let stack = &mut self.stack;
-        parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
-    }
-}
-
-pub fn get_attr<'a>(attrs: &'a [ast::Attribute], name: &'static str) -> impl Iterator<Item = &'a ast::Attribute> {
-    attrs.iter().filter_map(move |attr| {
-        if attr.path.segments.len() == 2 && attr.path.segments[0].ident.to_string() == "clippy" && attr.path.segments[1].ident.to_string() == name {
-            Some(attr)
-        } else {
-            None
-        }
-    })
-}
-
-fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) {
-    for attr in get_attr(attrs, name) {
-        if let Some(ref value) = attr.value_str() {
-            if let Ok(value) = FromStr::from_str(&value.as_str()) {
-                f(value)
-            } else {
-                sess.span_err(attr.span, "not a number");
-            }
-        } else {
-            sess.span_err(attr.span, "bad clippy attribute");
-        }
-    }
-}
-
-/// Return the pre-expansion span if is this comes from an expansion of the
+/// Returns the pre-expansion span if is this comes from an expansion of the
 /// macro `name`.
 /// See also `is_direct_expn_of`.
-pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
+pub fn is_expn_of(mut span: Span, name: Symbol) -> Option<Span> {
     loop {
-        let span_name_span = span.ctxt()
+        let span_name_span = span
+            .ctxt()
             .outer()
             .expn_info()
             .map(|ei| (ei.format.name(), ei.call_site));
@@ -750,7 +700,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
     }
 }
 
-/// Return the pre-expansion span if is this directly comes from an expansion
+/// Returns the pre-expansion span if the span directly comes from an expansion
 /// of the macro `name`.
 /// The difference with `is_expn_of` is that in
 /// ```rust,ignore
@@ -759,8 +709,9 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 /// `bar!` by
 /// `is_direct_expn_of`.
-pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
-    let span_name_span = span.ctxt()
+pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option<Span> {
+    let span_name_span = span
+        .ctxt()
         .outer()
         .expn_info()
         .map(|ei| (ei.format.name(), ei.call_site));
@@ -771,82 +722,19 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
     }
 }
 
-/// Return the index of the character after the first camel-case component of
-/// `s`.
-pub fn camel_case_until(s: &str) -> usize {
-    let mut iter = s.char_indices();
-    if let Some((_, first)) = iter.next() {
-        if !first.is_uppercase() {
-            return 0;
-        }
-    } else {
-        return 0;
-    }
-    let mut up = true;
-    let mut last_i = 0;
-    for (i, c) in iter {
-        if up {
-            if c.is_lowercase() {
-                up = false;
-            } else {
-                return last_i;
-            }
-        } else if c.is_uppercase() {
-            up = true;
-            last_i = i;
-        } else if !c.is_lowercase() {
-            return i;
-        }
-    }
-    if up {
-        last_i
-    } else {
-        s.len()
-    }
-}
-
-/// Return index of the last camel-case component of `s`.
-pub fn camel_case_from(s: &str) -> usize {
-    let mut iter = s.char_indices().rev();
-    if let Some((_, first)) = iter.next() {
-        if !first.is_lowercase() {
-            return s.len();
-        }
-    } else {
-        return s.len();
-    }
-    let mut down = true;
-    let mut last_i = s.len();
-    for (i, c) in iter {
-        if down {
-            if c.is_uppercase() {
-                down = false;
-                last_i = i;
-            } else if !c.is_lowercase() {
-                return last_i;
-            }
-        } else if c.is_lowercase() {
-            down = true;
-        } else {
-            return last_i;
-        }
-    }
-    last_i
-}
-
-/// Convenience function to get the return type of a function
-pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Ty<'tcx> {
-    let fn_def_id = cx.tcx.hir.local_def_id(fn_item);
+/// Convenience function to get the return type of a function.
+pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: hir::HirId) -> Ty<'tcx> {
+    let fn_def_id = cx.tcx.hir().local_def_id_from_hir_id(fn_item);
     let ret_ty = cx.tcx.fn_sig(fn_def_id).output();
     cx.tcx.erase_late_bound_regions(&ret_ty)
 }
 
-/// Check if two types are the same.
+/// Checks if two types are the same.
 ///
 /// This discards any lifetime annotations, too.
-// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for
-// <'b> Foo<'b>` but
-// not for type parameters.
+//
+// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` ==
+// `for <'b> Foo<'b>`, but not for type parameters).
 pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
     let a = cx.tcx.erase_late_bound_regions(&Binder::bind(a));
     let b = cx.tcx.erase_late_bound_regions(&Binder::bind(b));
@@ -855,24 +743,37 @@ pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
         .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok())
 }
 
-/// Return whether the given type is an `unsafe` function.
+/// Returns `true` if the given type is an `unsafe` function.
 pub fn type_is_unsafe_function<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.sty {
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
+        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
         _ => false,
     }
 }
 
 pub fn is_copy<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
-    !ty.moves_by_default(cx.tcx.global_tcx(), cx.param_env, DUMMY_SP)
+    ty.is_copy_modulo_regions(cx.tcx.global_tcx(), cx.param_env, DUMMY_SP)
 }
 
-/// Return whether a pattern is refutable.
+/// Checks if an expression is constructing a tuple-like enum variant or struct
+pub fn is_ctor_function(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
+    if let ExprKind::Call(ref fun, _) = expr.node {
+        if let ExprKind::Path(ref qp) = fun.node {
+            return matches!(
+                cx.tables.qpath_res(qp, fun.hir_id),
+                def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(..), _)
+            );
+        }
+    }
+    false
+}
+
+/// Returns `true` if a pattern is refutable.
 pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat) -> bool {
     fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath, id: HirId) -> bool {
         matches!(
-            cx.tables.qpath_def(qpath, id),
-            def::Def::Variant(..) | def::Def::VariantCtor(..)
+            cx.tables.qpath_res(qpath, id),
+            def::Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
         )
     }
 
@@ -886,30 +787,30 @@ fn are_refutable<'a, I: Iterator<Item = &'a Pat>>(cx: &LateContext<'_, '_>, mut
         PatKind::Lit(..) | PatKind::Range(..) => true,
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
         PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
-        PatKind::Struct(ref qpath, ref fields, _) => if is_enum_variant(cx, qpath, pat.hir_id) {
-            true
-        } else {
-            are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
+        PatKind::Struct(ref qpath, ref fields, _) => {
+            if is_enum_variant(cx, qpath, pat.hir_id) {
+                true
+            } else {
+                are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
+            }
         },
-        PatKind::TupleStruct(ref qpath, ref pats, _) => if is_enum_variant(cx, qpath, pat.hir_id) {
-            true
-        } else {
-            are_refutable(cx, pats.iter().map(|pat| &**pat))
+        PatKind::TupleStruct(ref qpath, ref pats, _) => {
+            if is_enum_variant(cx, qpath, pat.hir_id) {
+                true
+            } else {
+                are_refutable(cx, pats.iter().map(|pat| &**pat))
+            }
+        },
+        PatKind::Slice(ref head, ref middle, ref tail) => {
+            are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
         },
-        PatKind::Slice(ref head, ref middle, ref tail) => are_refutable(
-            cx,
-            head.iter()
-                .chain(middle)
-                .chain(tail.iter())
-                .map(|pat| &**pat),
-        ),
     }
 }
 
 /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 /// implementations have.
 pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
-    attr::contains_name(attrs, "automatically_derived")
+    attr::contains_name(attrs, *sym::automatically_derived)
 }
 
 /// Remove blocks around an expression.
@@ -932,38 +833,9 @@ pub fn remove_blocks(expr: &Expr) -> &Expr {
     }
 }
 
-pub fn opt_def_id(def: Def) -> Option<DefId> {
-    match def {
-        Def::Fn(id) |
-        Def::Mod(id) |
-        Def::Static(id, _) |
-        Def::Variant(id) |
-        Def::VariantCtor(id, ..) |
-        Def::Enum(id) |
-        Def::TyAlias(id) |
-        Def::AssociatedTy(id) |
-        Def::TyParam(id) |
-        Def::TyForeign(id) |
-        Def::Struct(id) |
-        Def::StructCtor(id, ..) |
-        Def::Union(id) |
-        Def::Trait(id) |
-        Def::TraitAlias(id) |
-        Def::Method(id) |
-        Def::Const(id) |
-        Def::AssociatedConst(id) |
-        Def::Macro(id, ..) |
-        Def::Existential(id) |
-        Def::AssociatedExistential(id) |
-        Def::GlobalAsm(id) => Some(id),
-
-        Def::Upvar(..) | Def::Local(_) | Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
-    }
-}
-
 pub fn is_self(slf: &Arg) -> bool {
-    if let PatKind::Binding(_, _, name, _) = slf.pat.node {
-        name.name == keywords::SelfValue.name()
+    if let PatKind::Binding(.., name, _) = slf.pat.node {
+        name.name == keywords::SelfLower.name()
     } else {
         false
     }
@@ -973,7 +845,7 @@ pub fn is_self_ty(slf: &hir::Ty) -> bool {
     if_chain! {
         if let TyKind::Path(ref qp) = slf.node;
         if let QPath::Resolved(None, ref path) = *qp;
-        if let Def::SelfTy(..) = path.def;
+        if let Res::SelfTy(..) = path.res;
         then {
             return true
         }
@@ -985,17 +857,17 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl, body: &'tcx Body) -> impl Iterator<I
     (0..decl.inputs.len()).map(move |i| &body.arguments[i])
 }
 
-/// Check if a given expression is a match expression
-/// expanded from `?` operator or `try` macro.
+/// Checks if a given expression is a match expression expanded from the `?`
+/// operator or the `try` macro.
 pub fn is_try(expr: &Expr) -> Option<&Expr> {
     fn is_ok(arm: &Arm) -> bool {
         if_chain! {
             if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pats[0].node;
             if match_qpath(path, &paths::RESULT_OK[1..]);
-            if let PatKind::Binding(_, defid, _, None) = pat[0].node;
+            if let PatKind::Binding(_, hir_id, _, None) = pat[0].node;
             if let ExprKind::Path(QPath::Resolved(None, ref path)) = arm.body.node;
-            if let Def::Local(lid) = path.def;
-            if lid == defid;
+            if let Res::Local(lid) = path.res;
+            if lid == hir_id;
             then {
                 return true;
             }
@@ -1032,39 +904,35 @@ fn is_err(arm: &Arm) -> bool {
     None
 }
 
-/// Returns true if the lint is allowed in the current context
+/// Returns `true` if the lint is allowed in the current context
 ///
 /// Useful for skipping long running code when it's unnecessary
-pub fn is_allowed(cx: &LateContext<'_, '_>, lint: &'static Lint, id: NodeId) -> bool {
+pub fn is_allowed(cx: &LateContext<'_, '_>, lint: &'static Lint, id: HirId) -> bool {
     cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 }
 
 pub fn get_arg_name(pat: &Pat) -> Option<ast::Name> {
     match pat.node {
-        PatKind::Binding(_, _, ident, None) => Some(ident.name),
+        PatKind::Binding(.., ident, None) => Some(ident.name),
         PatKind::Ref(ref subpat, _) => get_arg_name(subpat),
         _ => None,
     }
 }
 
-pub fn get_arg_ident(pat: &Pat) -> Option<ast::Ident> {
-    match pat.node {
-        PatKind::Binding(_, _, ident, None) => Some(ident),
-        PatKind::Ref(ref subpat, _) => get_arg_ident(subpat),
-        _ => None,
-    }
-}
-
 pub fn int_bits(tcx: TyCtxt<'_, '_, '_>, ity: ast::IntTy) -> u64 {
-    layout::Integer::from_attr(tcx, attr::IntType::SignedInt(ity)).size().bits()
+    layout::Integer::from_attr(&tcx, attr::IntType::SignedInt(ity))
+        .size()
+        .bits()
 }
 
+#[allow(clippy::cast_possible_wrap)]
 /// Turn a constant int byte representation into an i128
 pub fn sext(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::IntTy) -> i128 {
     let amt = 128 - int_bits(tcx, ity);
     ((u as i128) << amt) >> amt
 }
 
+#[allow(clippy::cast_sign_loss)]
 /// clip unused bytes
 pub fn unsext(tcx: TyCtxt<'_, '_, '_>, u: i128, ity: ast::IntTy) -> u128 {
     let amt = 128 - int_bits(tcx, ity);
@@ -1073,12 +941,14 @@ pub fn unsext(tcx: TyCtxt<'_, '_, '_>, u: i128, ity: ast::IntTy) -> u128 {
 
 /// clip unused bytes
 pub fn clip(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::UintTy) -> u128 {
-    let bits = layout::Integer::from_attr(tcx, attr::IntType::UnsignedInt(ity)).size().bits();
+    let bits = layout::Integer::from_attr(&tcx, attr::IntType::UnsignedInt(ity))
+        .size()
+        .bits();
     let amt = 128 - bits;
     (u << amt) >> amt
 }
 
-/// Remove block comments from the given Vec of lines
+/// Removes block comments from the given `Vec` of lines.
 ///
 /// # Examples
 ///
@@ -1111,16 +981,145 @@ pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> {
     without
 }
 
-pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_, '_, '_>, node: NodeId) -> bool {
-    let map = &tcx.hir;
+pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_, '_, '_>, node: HirId) -> bool {
+    let map = &tcx.hir();
     let mut prev_enclosing_node = None;
     let mut enclosing_node = node;
     while Some(enclosing_node) != prev_enclosing_node {
-        if is_automatically_derived(map.attrs(enclosing_node)) {
+        if is_automatically_derived(map.attrs_by_hir_id(enclosing_node)) {
             return true;
         }
         prev_enclosing_node = Some(enclosing_node);
-        enclosing_node = map.get_parent(enclosing_node);
+        enclosing_node = map.get_parent_item(enclosing_node);
     }
     false
 }
+
+/// Returns true if ty has `iter` or `iter_mut` methods
+pub fn has_iter_method(cx: &LateContext<'_, '_>, probably_ref_ty: Ty<'_>) -> Option<Symbol> {
+    // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
+    // exists and has the desired signature. Unfortunately FnCtxt is not exported
+    // so we can't use its `lookup_method` method.
+    let into_iter_collections: [&[Symbol]; 13] = [
+        &*paths::VEC,
+        &*paths::OPTION,
+        &*paths::RESULT,
+        &*paths::BTREESET,
+        &*paths::BTREEMAP,
+        &*paths::VEC_DEQUE,
+        &*paths::LINKED_LIST,
+        &*paths::BINARY_HEAP,
+        &*paths::HASHSET,
+        &*paths::HASHMAP,
+        &*paths::PATH_BUF,
+        &*paths::PATH,
+        &*paths::RECEIVER,
+    ];
+
+    let ty_to_check = match probably_ref_ty.sty {
+        ty::Ref(_, ty_to_check, _) => ty_to_check,
+        _ => probably_ref_ty,
+    };
+
+    let def_id = match ty_to_check.sty {
+        ty::Array(..) => return Some(*sym::array),
+        ty::Slice(..) => return Some(*sym::slice),
+        ty::Adt(adt, _) => adt.did,
+        _ => return None,
+    };
+
+    for path in &into_iter_collections {
+        if match_def_path(cx, def_id, path) {
+            return Some(*path.last().unwrap());
+        }
+    }
+    None
+}
+
+#[cfg(test)]
+mod test {
+    use super::{trim_multiline, without_block_comments};
+
+    #[test]
+    fn test_trim_multiline_single_line() {
+        assert_eq!("", trim_multiline("".into(), false));
+        assert_eq!("...", trim_multiline("...".into(), false));
+        assert_eq!("...", trim_multiline("    ...".into(), false));
+        assert_eq!("...", trim_multiline("\t...".into(), false));
+        assert_eq!("...", trim_multiline("\t\t...".into(), false));
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn test_trim_multiline_block() {
+        assert_eq!("\
+    if x {
+        y
+    } else {
+        z
+    }", trim_multiline("    if x {
+            y
+        } else {
+            z
+        }".into(), false));
+        assert_eq!("\
+    if x {
+    \ty
+    } else {
+    \tz
+    }", trim_multiline("    if x {
+        \ty
+        } else {
+        \tz
+        }".into(), false));
+    }
+
+    #[test]
+    #[rustfmt::skip]
+    fn test_trim_multiline_empty_line() {
+        assert_eq!("\
+    if x {
+        y
+
+    } else {
+        z
+    }", trim_multiline("    if x {
+            y
+
+        } else {
+            z
+        }".into(), false));
+    }
+
+    #[test]
+    fn test_without_block_comments_lines_without_block_comments() {
+        let result = without_block_comments(vec!["/*", "", "*/"]);
+        println!("result: {:?}", result);
+        assert!(result.is_empty());
+
+        let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
+        assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
+
+        let result = without_block_comments(vec!["/* rust", "", "*/"]);
+        assert!(result.is_empty());
+
+        let result = without_block_comments(vec!["/* one-line comment */"]);
+        assert!(result.is_empty());
+
+        let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
+        assert!(result.is_empty());
+
+        let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
+        assert!(result.is_empty());
+
+        let result = without_block_comments(vec!["foo", "bar", "baz"]);
+        assert_eq!(result, vec!["foo", "bar", "baz"]);
+    }
+}
+
+pub fn match_def_path<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, did: DefId, syms: &[Symbol]) -> bool {
+    // HACK: fix upstream `match_def_path` to take symbols
+    let syms: Vec<_> = syms.iter().map(|sym| sym.as_str()).collect();
+    let syms: Vec<_> = syms.iter().map(|sym| &**sym).collect();
+    cx.match_def_path(did, &syms)
+}
index 4d89f8ddffbbfbe424edea905fdfbeee756b089c..46c2de74d72030e6051ffb9e12072d2f5ffdaf98 100644 (file)
 //! This module contains paths to types and functions Clippy needs to know
 //! about.
 
-pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"];
-pub const ARC: [&str; 3] = ["alloc", "sync", "Arc"];
-pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
-pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
-pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
-pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"];
-pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"];
-pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
-pub const BOX: [&str; 3] = ["std", "boxed", "Box"];
-pub const BOX_NEW: [&str; 4] = ["std", "boxed", "Box", "new"];
-pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"];
-pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"];
-pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"];
-pub const CLONE: [&str; 4] = ["core", "clone", "Clone", "clone"];
-pub const CLONE_TRAIT: [&str; 3] = ["core", "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 C_VOID: [&str; 4] = ["std", "os", "raw", "c_void"];
-pub const C_VOID_LIBC: [&str; 2] = ["libc", "c_void"];
-pub const DEBUG_FMT_METHOD: [&str; 4] = ["core", "fmt", "Debug", "fmt"];
-pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"];
-pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
-pub const DISPLAY_FMT_METHOD: [&str; 4] = ["core", "fmt", "Display", "fmt"];
-pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
-pub const DROP: [&str; 3] = ["core", "mem", "drop"];
-pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
-pub const FMT_ARGUMENTS_NEWV1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
-pub const FMT_ARGUMENTS_NEWV1FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
-pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
-pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
-pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
-pub const HASH: [&str; 2] = ["hash", "Hash"];
-pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
-pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
-pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"];
-pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
-pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
-pub const INIT: [&str; 4] = ["core", "intrinsics", "", "init"];
-pub const INTO: [&str; 3] = ["core", "convert", "Into"];
-pub const INTO_ITERATOR: [&str; 4] = ["core", "iter", "traits", "IntoIterator"];
-pub const IO_PRINT: [&str; 4] = ["std", "io", "stdio", "_print"];
-pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
-pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
-pub const ITERATOR: [&str; 4] = ["core", "iter", "iterator", "Iterator"];
-pub const LINKED_LIST: [&str; 4] = ["alloc", "collections", "linked_list", "LinkedList"];
-pub const LINT: [&str; 2] = ["lint", "Lint"];
-pub const LINT_ARRAY: [&str; 2] = ["lint", "LintArray"];
-pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
-pub const MEM_UNINIT: [&str; 3] = ["core", "mem", "uninitialized"];
-pub const MEM_ZEROED: [&str; 3] = ["core", "mem", "zeroed"];
-pub const MUTEX: [&str; 4] = ["std", "sync", "mutex", "Mutex"];
-pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
-pub const OPS_MODULE: [&str; 2] = ["core", "ops"];
-pub const OPTION: [&str; 3] = ["core", "option", "Option"];
-pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
-pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
-pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
-pub const PARTIAL_ORD: [&str; 3] = ["core", "cmp", "PartialOrd"];
-pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
-pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
-pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
-pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
-pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
-pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
-pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"];
-pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
-pub const RANGE_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeInclusive"];
-pub const RANGE_INCLUSIVE_NEW: [&str; 4] = ["core", "ops", "RangeInclusive", "new"];
-pub const RANGE_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeInclusive"];
-pub const RANGE_INCLUSIVE_STD_NEW: [&str; 4] = ["std", "ops", "RangeInclusive", "new"];
-pub const RANGE_STD: [&str; 3] = ["std", "ops", "Range"];
-pub const RANGE_TO: [&str; 3] = ["core", "ops", "RangeTo"];
-pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"];
-pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"];
-pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
-pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
-pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"];
-pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
-pub const REGEX_BYTES: [&str; 3] = ["regex", "re_bytes", "Regex"];
-pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
-pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
-pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
-pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
-pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
-pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
-pub const RESULT: [&str; 3] = ["core", "result", "Result"];
-pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
-pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
-pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
-pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
-pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
-pub const STRING: [&str; 3] = ["alloc", "string", "String"];
-pub const TO_OWNED: [&str; 3] = ["alloc", "borrow", "ToOwned"];
-pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
-pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
-pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
-pub const UNINIT: [&str; 4] = ["core", "intrinsics", "", "uninit"];
-pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
-pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
-pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
-pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
-pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
+#![allow(default_hash_types)] // we just look at symbol names, which is good enough everywhere else
+
+use super::sym::{self, *};
+use lazy_static::lazy_static;
+use syntax::symbol::Symbol;
+
+lazy_static! {
+    pub static ref ANY_TRAIT: [Symbol; 3] = [*std, *any, *Any];
+    pub static ref ARC: [Symbol; 3] = [*alloc, *sync, *Arc];
+    pub static ref ASMUT_TRAIT: [Symbol; 3] = [*core, *convert, *sym::AsMut];
+    pub static ref ASREF_TRAIT: [Symbol; 3] = [*core, *convert, *sym::AsRef];
+    pub static ref BEGIN_PANIC: [Symbol; 3] = [*std, *panicking, *begin_panic];
+    pub static ref BEGIN_PANIC_FMT: [Symbol; 3] = [*std, *panicking, *begin_panic_fmt];
+    pub static ref BINARY_HEAP: [Symbol; 4] = [*alloc, *collections, *binary_heap, *BinaryHeap];
+    pub static ref BORROW_TRAIT: [Symbol; 3] = [*core, *borrow, *Borrow];
+    pub static ref BTREEMAP: [Symbol; 5] = [*alloc, *collections, *btree, *map, *BTreeMap];
+    pub static ref BTREEMAP_ENTRY: [Symbol; 5] = [*alloc, *collections, *btree, *map, *Entry];
+    pub static ref BTREESET: [Symbol; 5] = [*alloc, *collections, *btree, *set, *BTreeSet];
+    pub static ref CLONE_TRAIT: [Symbol; 3] = [*core, *clone, *sym::Clone];
+    pub static ref CLONE_TRAIT_METHOD: [Symbol; 4] = [*core, *clone, *sym::Clone, *clone];
+    pub static ref CMP_MAX: [Symbol; 3] = [*core, *cmp, *max];
+    pub static ref CMP_MIN: [Symbol; 3] = [*core, *cmp, *min];
+    pub static ref COW: [Symbol; 3] = [*alloc, *borrow, *Cow];
+    pub static ref CSTRING_NEW: [Symbol; 5] = [*std, *ffi, *c_str, *CString, *new];
+    pub static ref DEFAULT_TRAIT: [Symbol; 3] = [*core, *default, *sym::Default];
+    pub static ref DEFAULT_TRAIT_METHOD: [Symbol; 4] = [*core, *default, *sym::Default, *default];
+    pub static ref DEREF_TRAIT_METHOD: [Symbol; 5] = [*core, *ops, *deref, *Deref, *deref];
+    pub static ref DISPLAY_FMT_METHOD: [Symbol; 4] = [*core, *fmt, *Display, *fmt];
+    pub static ref DOUBLE_ENDED_ITERATOR: [Symbol; 4] = [*core, *iter, *traits, *sym::DoubleEndedIterator];
+    pub static ref DROP: [Symbol; 3] = [*core, *mem, *drop];
+    pub static ref DROP_TRAIT: [Symbol; 4] = [*core, *ops, *drop, *sym::Drop];
+    pub static ref DURATION: [Symbol; 3] = [*core, *time, *Duration];
+    pub static ref EARLY_CONTEXT: [Symbol; 4] = [*rustc, *lint, *context, *EarlyContext];
+    pub static ref FMT_ARGUMENTS_NEWV1: [Symbol; 4] = [*core, *fmt, *Arguments, *new_v1];
+    pub static ref FMT_ARGUMENTS_NEWV1FORMATTED: [Symbol; 4] = [*core, *fmt, *Arguments, *new_v1_formatted];
+    pub static ref FROM_FROM: [Symbol; 4] = [*core, *convert, *sym::From, *from];
+    pub static ref FROM_TRAIT: [Symbol; 3] = [*core, *convert, *sym::From];
+    pub static ref HASH: [Symbol; 2] = [*hash, *Hash];
+    pub static ref HASHMAP: [Symbol; 5] = [*std, *collections, *hash, *map, *HashMap];
+    pub static ref HASHMAP_ENTRY: [Symbol; 5] = [*std, *collections, *hash, *map, *Entry];
+    pub static ref HASHSET: [Symbol; 5] = [*std, *collections, *hash, *set, *HashSet];
+    pub static ref INDEX: [Symbol; 3] = [*core, *ops, *Index];
+    pub static ref INDEX_MUT: [Symbol; 3] = [*core, *ops, *IndexMut];
+    pub static ref INIT: [Symbol; 4] = [*core, *intrinsics, *empty_symbol, *init];
+    pub static ref INTO: [Symbol; 3] = [*core, *convert, *sym::Into];
+    pub static ref INTO_ITERATOR: [Symbol; 5] = [*core, *iter, *traits, *collect, *sym::IntoIterator];
+    pub static ref IO_READ: [Symbol; 3] = [*std, *io, *Read];
+    pub static ref IO_WRITE: [Symbol; 3] = [*std, *io, *Write];
+    pub static ref ITERATOR: [Symbol; 5] = [*core, *iter, *traits, *iterator, *sym::Iterator];
+    pub static ref LATE_CONTEXT: [Symbol; 4] = [*rustc, *lint, *context, *LateContext];
+    pub static ref LINKED_LIST: [Symbol; 4] = [*alloc, *collections, *linked_list, *LinkedList];
+    pub static ref LINT: [Symbol; 3] = [*rustc, *lint, *Lint];
+    pub static ref LINT_PASS: [Symbol; 3] = [*rustc, *lint, *LintPass];
+    pub static ref MEM_DISCRIMINANT: [Symbol; 3] = [*core, *mem, *discriminant];
+    pub static ref MEM_FORGET: [Symbol; 3] = [*core, *mem, *forget];
+    pub static ref MEM_REPLACE: [Symbol; 3] = [*core, *mem, *replace];
+    pub static ref MEM_UNINIT: [Symbol; 3] = [*core, *mem, *uninitialized];
+    pub static ref MEM_ZEROED: [Symbol; 3] = [*core, *mem, *zeroed];
+    pub static ref MUTEX: [Symbol; 4] = [*std, *sync, *mutex, *Mutex];
+    pub static ref OPEN_OPTIONS: [Symbol; 3] = [*std, *fs, *OpenOptions];
+    pub static ref OPS_MODULE: [Symbol; 2] = [*core, *ops];
+    pub static ref OPTION: [Symbol; 3] = [*core, *option, *sym::Option];
+    pub static ref OPTION_NONE: [Symbol; 4] = [*core, *option, *sym::Option, *sym::None];
+    pub static ref OPTION_SOME: [Symbol; 4] = [*core, *option, *sym::Option, *sym::Some];
+    pub static ref ORD: [Symbol; 3] = [*core, *cmp, *sym::Ord];
+    pub static ref OS_STRING: [Symbol; 4] = [*std, *ffi, *os_str, *OsString];
+    pub static ref OS_STR_TO_OS_STRING: [Symbol; 5] = [*std, *ffi, *os_str, *OsStr, *to_os_string];
+    pub static ref PARTIAL_ORD: [Symbol; 3] = [*core, *cmp, *sym::PartialOrd];
+    pub static ref PATH: [Symbol; 3] = [*std, *path, *Path];
+    pub static ref PATH_BUF: [Symbol; 3] = [*std, *path, *PathBuf];
+    pub static ref PATH_TO_PATH_BUF: [Symbol; 4] = [*std, *path, *Path, *to_path_buf];
+    pub static ref PTR_NULL: [Symbol; 2] = [*ptr, *null];
+    pub static ref PTR_NULL_MUT: [Symbol; 2] = [*ptr, *null_mut];
+    pub static ref RANGE: [Symbol; 3] = [*core, *ops, *Range];
+    pub static ref RANGE_ARGUMENT_TRAIT: [Symbol; 3] = [*core, *ops, *RangeBounds];
+    pub static ref RANGE_FROM: [Symbol; 3] = [*core, *ops, *RangeFrom];
+    pub static ref RANGE_FROM_STD: [Symbol; 3] = [*std, *ops, *RangeFrom];
+    pub static ref RANGE_FULL: [Symbol; 3] = [*core, *ops, *RangeFull];
+    pub static ref RANGE_FULL_STD: [Symbol; 3] = [*std, *ops, *RangeFull];
+    pub static ref RANGE_INCLUSIVE_NEW: [Symbol; 4] = [*core, *ops, *RangeInclusive, *new];
+    pub static ref RANGE_INCLUSIVE_STD_NEW: [Symbol; 4] = [*std, *ops, *RangeInclusive, *new];
+    pub static ref RANGE_STD: [Symbol; 3] = [*std, *ops, *Range];
+    pub static ref RANGE_TO: [Symbol; 3] = [*core, *ops, *RangeTo];
+    pub static ref RANGE_TO_INCLUSIVE: [Symbol; 3] = [*core, *ops, *RangeToInclusive];
+    pub static ref RANGE_TO_INCLUSIVE_STD: [Symbol; 3] = [*std, *ops, *RangeToInclusive];
+    pub static ref RANGE_TO_STD: [Symbol; 3] = [*std, *ops, *RangeTo];
+    pub static ref RC: [Symbol; 3] = [*alloc, *rc, *Rc];
+    pub static ref RECEIVER: [Symbol; 4] = [*std, *sync, *mpsc, *Receiver];
+    pub static ref REGEX: [Symbol; 3] = [*regex, *re_unicode, *Regex];
+    pub static ref REGEX_BUILDER_NEW: [Symbol; 5] = [*regex, *re_builder, *unicode, *RegexBuilder, *new];
+    pub static ref REGEX_BYTES_BUILDER_NEW: [Symbol; 5] = [*regex, *re_builder, *bytes, *RegexBuilder, *new];
+    pub static ref REGEX_BYTES_NEW: [Symbol; 4] = [*regex, *re_bytes, *Regex, *new];
+    pub static ref REGEX_BYTES_SET_NEW: [Symbol; 5] = [*regex, *re_set, *bytes, *RegexSet, *new];
+    pub static ref REGEX_NEW: [Symbol; 4] = [*regex, *re_unicode, *Regex, *new];
+    pub static ref REGEX_SET_NEW: [Symbol; 5] = [*regex, *re_set, *unicode, *RegexSet, *new];
+    pub static ref REPEAT: [Symbol; 3] = [*core, *iter, *repeat];
+    pub static ref RESULT: [Symbol; 3] = [*core, *result, *sym::Result];
+    pub static ref RESULT_ERR: [Symbol; 4] = [*core, *result, *sym::Result, *sym::Err];
+    pub static ref RESULT_OK: [Symbol; 4] = [*core, *result, *sym::Result, *sym::Ok];
+    pub static ref SERDE_DE_VISITOR: [Symbol; 3] = [*serde, *de, *Visitor];
+    pub static ref SLICE_INTO_VEC: [Symbol; 4] = [*alloc, *slice, *impl_slice_t, *into_vec];
+    pub static ref SLICE_ITER: [Symbol; 3] = [*core, *slice, *Iter];
+    pub static ref STD_MEM_TRANSMUTE: [Symbol; 3] = [*std, *mem, *transmute];
+    pub static ref STD_PTR_NULL: [Symbol; 3] = [*std, *ptr, *null];
+    pub static ref STDERR: [Symbol; 4] = [*std, *io, *stdio, *stderr];
+    pub static ref STDOUT: [Symbol; 4] = [*std, *io, *stdio, *stdout];
+    pub static ref STRING: [Symbol; 3] = [*alloc, *string, *sym::String];
+    pub static ref TO_OWNED: [Symbol; 3] = [*alloc, *borrow, *sym::ToOwned];
+    pub static ref TO_OWNED_METHOD: [Symbol; 4] = [*alloc, *borrow, *sym::ToOwned, *to_owned];
+    pub static ref TO_STRING: [Symbol; 3] = [*alloc, *string, *sym::ToString];
+    pub static ref TO_STRING_METHOD: [Symbol; 4] = [*alloc, *string, *sym::ToString, *to_string];
+    pub static ref TRANSMUTE: [Symbol; 4] = [*core, *intrinsics, *empty_symbol, *transmute];
+    pub static ref TRY_INTO_RESULT: [Symbol; 4] = [*std, *ops, *Try, *into_result];
+    pub static ref UNINIT: [Symbol; 4] = [*core, *intrinsics, *empty_symbol, *uninit];
+    pub static ref VEC: [Symbol; 3] = [*alloc, *vec, *sym::Vec];
+    pub static ref VEC_DEQUE: [Symbol; 4] = [*alloc, *collections, *vec_deque, *VecDeque];
+    pub static ref VEC_FROM_ELEM: [Symbol; 3] = [*alloc, *vec, *from_elem];
+    pub static ref WEAK_ARC: [Symbol; 3] = [*alloc, *sync, *Weak];
+    pub static ref WEAK_RC: [Symbol; 3] = [*alloc, *rc, *Weak];
+}
index 1a20eb0101538b17533cd0916a2445b4fb25bdf0..a0096b2a653b8c561f85a3b2ab1f63ee396ed820 100644 (file)
@@ -1,20 +1,24 @@
-use std::borrow::Cow;
-use rustc::hir::*;
+use crate::utils::sym;
+use crate::utils::{get_pat_name, match_var, snippet};
 use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc::hir::*;
 use rustc::lint::LateContext;
+use std::borrow::Cow;
 use syntax::ast::Name;
-use syntax::codemap::Span;
-use crate::utils::{get_pat_name, match_var, snippet};
+use syntax::source_map::Span;
+use syntax::symbol::Symbol;
 
 pub fn get_spans(
     cx: &LateContext<'_, '_>,
     opt_body_id: Option<BodyId>,
     idx: usize,
-    replacements: &'static [(&'static str, &'static str)],
+    replacements: &[(Symbol, &'static str)],
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
-    if let Some(body) = opt_body_id.map(|id| cx.tcx.hir.body(id)) {
-        get_binding_name(&body.arguments[idx])
-            .map_or_else(|| Some(vec![]), |name| extract_clone_suggestions(cx, name, replacements, body))
+    if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
+        get_binding_name(&body.arguments[idx]).map_or_else(
+            || Some(vec![]),
+            |name| extract_clone_suggestions(cx, name, replacements, body),
+        )
     } else {
         Some(vec![])
     }
@@ -23,7 +27,7 @@ pub fn get_spans(
 fn extract_clone_suggestions<'a, 'tcx: 'a>(
     cx: &LateContext<'a, 'tcx>,
     name: Name,
-    replace: &'static [(&'static str, &'static str)],
+    replace: &[(Symbol, &'static str)],
     body: &'tcx Body,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     let mut visitor = PtrCloneVisitor {
@@ -44,7 +48,7 @@ fn extract_clone_suggestions<'a, 'tcx: 'a>(
 struct PtrCloneVisitor<'a, 'tcx: 'a> {
     cx: &'a LateContext<'a, 'tcx>,
     name: Name,
-    replace: &'static [(&'static str, &'static str)],
+    replace: &'a [(Symbol, &'static str)],
     spans: Vec<(Span, Cow<'static, str>)>,
     abort: bool,
 }
@@ -56,7 +60,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
         }
         if let ExprKind::MethodCall(ref seg, _, ref args) = expr.node {
             if args.len() == 1 && match_var(&args[0], self.name) {
-                if seg.ident.name == "capacity" {
+                if seg.ident.name == *sym::capacity {
                     self.abort = true;
                     return;
                 }
index 11187559bf6ad58ca76d6fe00842bc0d232b3211..4d87373ec6a9cd58fd5a87294e5a5e78a93133d2 100644 (file)
@@ -1,21 +1,21 @@
 //! Contains utility functions to generate suggestions.
-#![deny(missing_docs_in_private_items)]
-// currently ignores lifetimes and generics
-#![allow(use_self)]
+#![deny(clippy::missing_docs_in_private_items)]
 
+use crate::utils::{higher, in_macro_or_desugar, snippet, snippet_opt, snippet_with_macro_callsite};
 use matches::matches;
 use rustc::hir;
 use rustc::lint::{EarlyContext, LateContext, LintContext};
 use rustc_errors;
+use rustc_errors::Applicability;
+use std;
 use std::borrow::Cow;
+use std::convert::TryInto;
 use std::fmt::Display;
-use std;
-use syntax::codemap::{CharPos, Span};
+use syntax::ast;
 use syntax::parse::token;
 use syntax::print::pprust::token_to_string;
+use syntax::source_map::{CharPos, Span};
 use syntax::util::parser::AssocOp;
-use syntax::ast;
-use crate::utils::{higher, snippet, snippet_opt};
 use syntax_pos::{BytePos, Pos};
 
 /// A helper type to build suggestion correctly handling parenthesis.
@@ -40,43 +40,13 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
     }
 }
 
-#[allow(wrong_self_convention)] // ok, because of the function `as_ty` method
+#[allow(clippy::wrong_self_convention)] // ok, because of the function `as_ty` method
 impl<'a> Sugg<'a> {
     /// Prepare a suggestion from an expression.
     pub fn hir_opt(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<Self> {
         snippet_opt(cx, expr.span).map(|snippet| {
             let snippet = Cow::Owned(snippet);
-            match expr.node {
-                hir::ExprKind::AddrOf(..) |
-                hir::ExprKind::Box(..) |
-                hir::ExprKind::Closure(.., _) |
-                hir::ExprKind::If(..) |
-                hir::ExprKind::Unary(..) |
-                hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
-                hir::ExprKind::Continue(..) |
-                hir::ExprKind::Yield(..) |
-                hir::ExprKind::Array(..) |
-                hir::ExprKind::Block(..) |
-                hir::ExprKind::Break(..) |
-                hir::ExprKind::Call(..) |
-                hir::ExprKind::Field(..) |
-                hir::ExprKind::Index(..) |
-                hir::ExprKind::InlineAsm(..) |
-                hir::ExprKind::Lit(..) |
-                hir::ExprKind::Loop(..) |
-                hir::ExprKind::MethodCall(..) |
-                hir::ExprKind::Path(..) |
-                hir::ExprKind::Repeat(..) |
-                hir::ExprKind::Ret(..) |
-                hir::ExprKind::Struct(..) |
-                hir::ExprKind::Tup(..) |
-                hir::ExprKind::While(..) => Sugg::NonParen(snippet),
-                hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
-                hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
-                hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(higher::binop(op.node)), snippet),
-                hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
-                hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
-            }
+            Self::hir_from_snippet(expr, snippet)
         })
     }
 
@@ -86,6 +56,74 @@ pub fn hir(cx: &LateContext<'_, '_>, expr: &hir::Expr, default: &'a str) -> Self
         Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default)))
     }
 
+    /// Same as `hir`, but it adapts the applicability level by following rules:
+    ///
+    /// - Applicability level `Unspecified` will never be changed.
+    /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
+    /// - If the default value is used and the applicability level is `MachineApplicable`, change it
+    ///   to
+    /// `HasPlaceholders`
+    pub fn hir_with_applicability(
+        cx: &LateContext<'_, '_>,
+        expr: &hir::Expr,
+        default: &'a str,
+        applicability: &mut Applicability,
+    ) -> Self {
+        if *applicability != Applicability::Unspecified && in_macro_or_desugar(expr.span) {
+            *applicability = Applicability::MaybeIncorrect;
+        }
+        Self::hir_opt(cx, expr).unwrap_or_else(|| {
+            if *applicability == Applicability::MachineApplicable {
+                *applicability = Applicability::HasPlaceholders;
+            }
+            Sugg::NonParen(Cow::Borrowed(default))
+        })
+    }
+
+    /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro.
+    pub fn hir_with_macro_callsite(cx: &LateContext<'_, '_>, expr: &hir::Expr, default: &'a str) -> Self {
+        let snippet = snippet_with_macro_callsite(cx, expr.span, default);
+
+        Self::hir_from_snippet(expr, snippet)
+    }
+
+    /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
+    /// function variants of `Sugg`, since these use different snippet functions.
+    fn hir_from_snippet(expr: &hir::Expr, snippet: Cow<'a, str>) -> Self {
+        match expr.node {
+            hir::ExprKind::AddrOf(..)
+            | hir::ExprKind::Box(..)
+            | hir::ExprKind::Closure(.., _)
+            | hir::ExprKind::Unary(..)
+            | hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
+            hir::ExprKind::Continue(..)
+            | hir::ExprKind::Yield(..)
+            | hir::ExprKind::Array(..)
+            | hir::ExprKind::Block(..)
+            | hir::ExprKind::Break(..)
+            | hir::ExprKind::Call(..)
+            | hir::ExprKind::Field(..)
+            | hir::ExprKind::Index(..)
+            | hir::ExprKind::InlineAsm(..)
+            | hir::ExprKind::Lit(..)
+            | hir::ExprKind::Loop(..)
+            | hir::ExprKind::MethodCall(..)
+            | hir::ExprKind::Path(..)
+            | hir::ExprKind::Repeat(..)
+            | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Struct(..)
+            | hir::ExprKind::Tup(..)
+            | hir::ExprKind::While(..)
+            | hir::ExprKind::DropTemps(_)
+            | hir::ExprKind::Err => Sugg::NonParen(snippet),
+            hir::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
+            hir::ExprKind::AssignOp(op, ..) => Sugg::BinOp(hirbinop2assignop(op), snippet),
+            hir::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(higher::binop(op.node)), snippet),
+            hir::ExprKind::Cast(..) => Sugg::BinOp(AssocOp::As, snippet),
+            hir::ExprKind::Type(..) => Sugg::BinOp(AssocOp::Colon, snippet),
+        }
+    }
+
     /// Prepare a suggestion from an expression.
     pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
         use syntax::ast::RangeLimits;
@@ -93,39 +131,41 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
         let snippet = snippet(cx, expr.span, default);
 
         match expr.node {
-            ast::ExprKind::AddrOf(..) |
-            ast::ExprKind::Box(..) |
-            ast::ExprKind::Closure(..) |
-            ast::ExprKind::If(..) |
-            ast::ExprKind::IfLet(..) |
-            ast::ExprKind::ObsoleteInPlace(..) |
-            ast::ExprKind::Unary(..) |
-            ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
-            ast::ExprKind::Async(..) |
-            ast::ExprKind::Block(..) |
-            ast::ExprKind::Break(..) |
-            ast::ExprKind::Call(..) |
-            ast::ExprKind::Catch(..) |
-            ast::ExprKind::Continue(..) |
-            ast::ExprKind::Yield(..) |
-            ast::ExprKind::Field(..) |
-            ast::ExprKind::ForLoop(..) |
-            ast::ExprKind::Index(..) |
-            ast::ExprKind::InlineAsm(..) |
-            ast::ExprKind::Lit(..) |
-            ast::ExprKind::Loop(..) |
-            ast::ExprKind::Mac(..) |
-            ast::ExprKind::MethodCall(..) |
-            ast::ExprKind::Paren(..) |
-            ast::ExprKind::Path(..) |
-            ast::ExprKind::Repeat(..) |
-            ast::ExprKind::Ret(..) |
-            ast::ExprKind::Struct(..) |
-            ast::ExprKind::Try(..) |
-            ast::ExprKind::Tup(..) |
-            ast::ExprKind::Array(..) |
-            ast::ExprKind::While(..) |
-            ast::ExprKind::WhileLet(..) => Sugg::NonParen(snippet),
+            ast::ExprKind::AddrOf(..)
+            | ast::ExprKind::Box(..)
+            | ast::ExprKind::Closure(..)
+            | ast::ExprKind::If(..)
+            | ast::ExprKind::IfLet(..)
+            | ast::ExprKind::ObsoleteInPlace(..)
+            | ast::ExprKind::Unary(..)
+            | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet),
+            ast::ExprKind::Async(..)
+            | ast::ExprKind::Block(..)
+            | ast::ExprKind::Break(..)
+            | ast::ExprKind::Call(..)
+            | ast::ExprKind::Continue(..)
+            | ast::ExprKind::Yield(..)
+            | ast::ExprKind::Field(..)
+            | ast::ExprKind::ForLoop(..)
+            | ast::ExprKind::Index(..)
+            | ast::ExprKind::InlineAsm(..)
+            | ast::ExprKind::Lit(..)
+            | ast::ExprKind::Loop(..)
+            | ast::ExprKind::Mac(..)
+            | ast::ExprKind::MethodCall(..)
+            | ast::ExprKind::Paren(..)
+            | ast::ExprKind::Path(..)
+            | ast::ExprKind::Repeat(..)
+            | ast::ExprKind::Ret(..)
+            | ast::ExprKind::Struct(..)
+            | ast::ExprKind::Try(..)
+            | ast::ExprKind::TryBlock(..)
+            | ast::ExprKind::Tup(..)
+            | ast::ExprKind::Array(..)
+            | ast::ExprKind::While(..)
+            | ast::ExprKind::WhileLet(..)
+            | ast::ExprKind::Await(..)
+            | ast::ExprKind::Err => Sugg::NonParen(snippet),
             ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet),
             ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet),
             ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet),
@@ -141,6 +181,11 @@ pub fn and(self, rhs: &Self) -> Sugg<'static> {
         make_binop(ast::BinOpKind::And, &self, rhs)
     }
 
+    /// Convenience method to create the `<lhs> & <rhs>` suggestion.
+    pub fn bit_and(self, rhs: &Self) -> Sugg<'static> {
+        make_binop(ast::BinOpKind::BitAnd, &self, rhs)
+    }
+
     /// Convenience method to create the `<lhs> as <rhs>` suggestion.
     pub fn as_ty<R: Display>(self, rhs: R) -> Sugg<'static> {
         make_assoc(AssocOp::As, &self, &Sugg::NonParen(rhs.to_string().into()))
@@ -175,8 +220,20 @@ pub fn mut_addr_deref(self) -> Sugg<'static> {
         make_unop("&mut *", self)
     }
 
+    /// Convenience method to transform suggestion into a return call
+    pub fn make_return(self) -> Sugg<'static> {
+        Sugg::NonParen(Cow::Owned(format!("return {}", self)))
+    }
+
+    /// Convenience method to transform suggestion into a block
+    /// where the suggestion is a trailing expression
+    pub fn blockify(self) -> Sugg<'static> {
+        Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
+    }
+
     /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
     /// suggestion.
+    #[allow(dead_code)]
     pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
         match limit {
             ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, end),
@@ -184,17 +241,19 @@ pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
         }
     }
 
-    /// Add parenthesis to any expression that might need them. Suitable to the
-    /// `self` argument of
-    /// a method call (eg. to build `bar.foo()` or `(1 + 2).foo()`).
+    /// Adds parenthesis to any expression that might need them. Suitable to the
+    /// `self` argument of a method call
+    /// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
     pub fn maybe_par(self) -> Self {
         match self {
             Sugg::NonParen(..) => self,
-            // (x) and (x).y() both don't need additional parens
-            Sugg::MaybeParen(sugg) => if sugg.starts_with('(') && sugg.ends_with(')') {
-                Sugg::MaybeParen(sugg)
-            } else {
-                Sugg::NonParen(format!("({})", sugg).into())
+            // `(x)` and `(x).y()` both don't need additional parens.
+            Sugg::MaybeParen(sugg) => {
+                if sugg.starts_with('(') && sugg.ends_with(')') {
+                    Sugg::MaybeParen(sugg)
+                } else {
+                    Sugg::NonParen(format!("({})", sugg).into())
+                }
             },
             Sugg::BinOp(_, sugg) => Sugg::NonParen(format!("({})", sugg).into()),
         }
@@ -224,19 +283,16 @@ fn not(self) -> Sugg<'static> {
 
 /// Helper type to display either `foo` or `(foo)`.
 struct ParenHelper<T> {
-    /// Whether parenthesis are needed.
+    /// `true` if parentheses are needed.
     paren: bool,
     /// The main thing to display.
     wrapped: T,
 }
 
 impl<T> ParenHelper<T> {
-    /// Build a `ParenHelper`.
+    /// Builds a `ParenHelper`.
     fn new(paren: bool, wrapped: T) -> Self {
-        Self {
-            paren,
-            wrapped,
-        }
+        Self { paren, wrapped }
     }
 }
 
@@ -250,7 +306,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
     }
 }
 
-/// Build the string for `<op><expr>` adding parenthesis when necessary.
+/// Builds the string for `<op><expr>` adding parenthesis when necessary.
 ///
 /// For convenience, the operator is taken as a string because all unary
 /// operators have the same
@@ -259,18 +315,19 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
     Sugg::MaybeParen(format!("{}{}", op, expr.maybe_par()).into())
 }
 
-/// Build the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
+/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
 ///
 /// Precedence of shift operator relative to other arithmetic operation is
 /// often confusing so
 /// parenthesis will always be added for a mix of these.
 pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
-    /// Whether the operator is a shift operator `<<` or `>>`.
+    /// Returns `true` if the operator is a shift operator `<<` or `>>`.
     fn is_shift(op: &AssocOp) -> bool {
         matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
     }
 
-    /// Whether the operator is a arithmetic operator (`+`, `-`, `*`, `/`, `%`).
+    /// Returns `true` if the operator is a arithmetic operator
+    /// (i.e., `+`, `-`, `*`, `/`, `%`).
     fn is_arith(op: &AssocOp) -> bool {
         matches!(
             *op,
@@ -278,15 +335,15 @@ fn is_arith(op: &AssocOp) -> bool {
         )
     }
 
-    /// Whether the operator `op` needs parenthesis with the operator `other`
-    /// in the direction
-    /// `dir`.
+    /// Returns `true` if the operator `op` needs parenthesis with the operator
+    /// `other` in the direction `dir`.
     fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
         other.precedence() < op.precedence()
             || (other.precedence() == op.precedence()
                 && ((op != other && associativity(op) != dir)
                     || (op == other && associativity(op) != Associativity::Both)))
-            || is_shift(op) && is_arith(other) || is_shift(other) && is_arith(op)
+            || is_shift(op) && is_arith(other)
+            || is_shift(other) && is_arith(op)
     }
 
     let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
@@ -304,24 +361,29 @@ fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
     let lhs = ParenHelper::new(lhs_paren, lhs);
     let rhs = ParenHelper::new(rhs_paren, rhs);
     let sugg = match op {
-        AssocOp::Add |
-        AssocOp::BitAnd |
-        AssocOp::BitOr |
-        AssocOp::BitXor |
-        AssocOp::Divide |
-        AssocOp::Equal |
-        AssocOp::Greater |
-        AssocOp::GreaterEqual |
-        AssocOp::LAnd |
-        AssocOp::LOr |
-        AssocOp::Less |
-        AssocOp::LessEqual |
-        AssocOp::Modulus |
-        AssocOp::Multiply |
-        AssocOp::NotEqual |
-        AssocOp::ShiftLeft |
-        AssocOp::ShiftRight |
-        AssocOp::Subtract => format!("{} {} {}", lhs, op.to_ast_binop().expect("Those are AST ops").to_string(), rhs),
+        AssocOp::Add
+        | AssocOp::BitAnd
+        | AssocOp::BitOr
+        | AssocOp::BitXor
+        | AssocOp::Divide
+        | AssocOp::Equal
+        | AssocOp::Greater
+        | AssocOp::GreaterEqual
+        | AssocOp::LAnd
+        | AssocOp::LOr
+        | AssocOp::Less
+        | AssocOp::LessEqual
+        | AssocOp::Modulus
+        | AssocOp::Multiply
+        | AssocOp::NotEqual
+        | AssocOp::ShiftLeft
+        | AssocOp::ShiftRight
+        | AssocOp::Subtract => format!(
+            "{} {} {}",
+            lhs,
+            op.to_ast_binop().expect("Those are AST ops").to_string(),
+            rhs
+        ),
         AssocOp::Assign => format!("{} = {}", lhs, rhs),
         AssocOp::ObsoleteInPlace => format!("in ({}) {}", lhs, rhs),
         AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_to_string(&token::BinOp(op)), rhs),
@@ -352,10 +414,9 @@ enum Associativity {
     Right,
 }
 
-/// Return the associativity/fixity of an operator. The difference with
-/// `AssocOp::fixity` is that
-/// an operator can be both left and right associative (such as `+`:
-/// `a + b + c == (a + b) + c == a + (b + c)`.
+/// Returns the associativity/fixity of an operator. The difference with
+/// `AssocOp::fixity` is that an operator can be both left and right associative
+/// (such as `+`: `a + b + c == (a + b) + c == a + (b + c)`.
 ///
 /// Chained `as` and explicit `:` type coercion never need inner parenthesis so
 /// they are considered
@@ -366,22 +427,13 @@ fn associativity(op: &AssocOp) -> Associativity {
     match *op {
         ObsoleteInPlace | Assign | AssignOp(_) => Associativity::Right,
         Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
-        Divide |
-        Equal |
-        Greater |
-        GreaterEqual |
-        Less |
-        LessEqual |
-        Modulus |
-        NotEqual |
-        ShiftLeft |
-        ShiftRight |
-        Subtract => Associativity::Left,
+        Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight
+        | Subtract => Associativity::Left,
         DotDot | DotDotEq => Associativity::None,
     }
 }
 
-/// Convert a `hir::BinOp` to the corresponding assigning binary operator.
+/// Converts a `hir::BinOp` to the corresponding assigning binary operator.
 fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
     use syntax::parse::token::BinOpToken::*;
 
@@ -397,19 +449,18 @@ fn hirbinop2assignop(op: hir::BinOp) -> AssocOp {
         hir::BinOpKind::Shr => Shr,
         hir::BinOpKind::Sub => Minus,
 
-        hir::BinOpKind::And
+        hir::BinOpKind::And
         | hir::BinOpKind::Eq
         | hir::BinOpKind::Ge
         | hir::BinOpKind::Gt
         | hir::BinOpKind::Le
         | hir::BinOpKind::Lt
         | hir::BinOpKind::Ne
-        | hir::BinOpKind::Or
-        => panic!("This operator does not exist"),
+        | hir::BinOpKind::Or => panic!("This operator does not exist"),
     })
 }
 
-/// Convert an `ast::BinOp` to the corresponding assigning binary operator.
+/// Converts an `ast::BinOp` to the corresponding assigning binary operator.
 fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
     use syntax::ast::BinOpKind::*;
     use syntax::parse::token::BinOpToken;
@@ -429,15 +480,13 @@ fn astbinop2assignop(op: ast::BinOp) -> AssocOp {
     })
 }
 
-/// Return the indentation before `span` if there are nothing but `[ \t]`
+/// Returns the indentation before `span` if there are nothing but `[ \t]`
 /// before it on its line.
 fn indentation<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String> {
-    let lo = cx.sess().codemap().lookup_char_pos(span.lo());
-    if let Some(line) = lo.file
-        .get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */)
-    {
+    let lo = cx.sess().source_map().lookup_char_pos(span.lo());
+    if let Some(line) = lo.file.get_line(lo.line - 1 /* line numbers in `Loc` are 1-based */) {
         if let Some((pos, _)) = line.char_indices().find(|&(_, c)| c != ' ' && c != '\t') {
-            // we can mix char and byte positions here because we only consider `[ \t]`
+            // We can mix char and byte positions here because we only consider `[ \t]`.
             if lo.col == CharPos(pos) {
                 Some(line[..pos].into())
             } else {
@@ -462,7 +511,14 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
     /// ```rust,ignore
     /// db.suggest_item_with_attr(cx, item, "#[derive(Default)]");
     /// ```
-    fn suggest_item_with_attr<D: Display + ?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D);
+    fn suggest_item_with_attr<D: Display + ?Sized>(
+        &mut self,
+        cx: &T,
+        item: Span,
+        msg: &str,
+        attr: &D,
+        applicability: Applicability,
+    );
 
     /// Suggest to add an item before another.
     ///
@@ -476,7 +532,7 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
     ///     bar();
     /// }");
     /// ```
-    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str);
+    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str, applicability: Applicability);
 
     /// Suggest to completely remove an item.
     ///
@@ -489,19 +545,26 @@ pub trait DiagnosticBuilderExt<'a, T: LintContext<'a>> {
     /// ```rust,ignore
     /// db.suggest_remove_item(cx, item, "remove this")
     /// ```
-    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str);
+    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability);
 }
 
 impl<'a, 'b, 'c, T: LintContext<'c>> DiagnosticBuilderExt<'c, T> for rustc_errors::DiagnosticBuilder<'b> {
-    fn suggest_item_with_attr<D: Display + ?Sized>(&mut self, cx: &T, item: Span, msg: &str, attr: &D) {
+    fn suggest_item_with_attr<D: Display + ?Sized>(
+        &mut self,
+        cx: &T,
+        item: Span,
+        msg: &str,
+        attr: &D,
+        applicability: Applicability,
+    ) {
         if let Some(indent) = indentation(cx, item) {
             let span = item.with_hi(item.lo());
 
-            self.span_suggestion(span, msg, format!("{}\n{}", attr, indent));
+            self.span_suggestion(span, msg, format!("{}\n{}", attr, indent), applicability);
         }
     }
 
-    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str) {
+    fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str, applicability: Applicability) {
         if let Some(indent) = indentation(cx, item) {
             let span = item.with_hi(item.lo());
 
@@ -518,23 +581,42 @@ fn suggest_prepend_item(&mut self, cx: &T, item: Span, msg: &str, new_item: &str
                 })
                 .collect::<String>();
 
-            self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent));
+            self.span_suggestion(span, msg, format!("{}\n{}", new_item, indent), applicability);
         }
     }
 
-    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str) {
+    fn suggest_remove_item(&mut self, cx: &T, item: Span, msg: &str, applicability: Applicability) {
         let mut remove_span = item;
-        let hi = cx.sess().codemap().next_point(remove_span).hi();
-        let fmpos = cx.sess().codemap().lookup_byte_offset(hi);
+        let hi = cx.sess().source_map().next_point(remove_span).hi();
+        let fmpos = cx.sess().source_map().lookup_byte_offset(hi);
 
-        if let Some(ref src) = fmpos.fm.src {
+        if let Some(ref src) = fmpos.sf.src {
             let non_whitespace_offset = src[fmpos.pos.to_usize()..].find(|c| c != ' ' && c != '\t' && c != '\n');
 
             if let Some(non_whitespace_offset) = non_whitespace_offset {
-                remove_span = remove_span.with_hi(remove_span.hi() + BytePos(non_whitespace_offset as u32))
+                remove_span = remove_span
+                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")))
             }
         }
 
-        self.span_suggestion(remove_span, msg, String::new());
+        self.span_suggestion(remove_span, msg, String::new(), applicability);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::Sugg;
+    use std::borrow::Cow;
+
+    const SUGGESTION: Sugg<'static> = Sugg::NonParen(Cow::Borrowed("function_call()"));
+
+    #[test]
+    fn make_return_transform_sugg_into_a_return_call() {
+        assert_eq!("return function_call()", SUGGESTION.make_return().to_string());
+    }
+
+    #[test]
+    fn blockify_transforms_sugg_into_a_block() {
+        assert_eq!("{ function_call() }", SUGGESTION.blockify().to_string());
     }
 }
diff --git a/clippy_lints/src/utils/sym.rs b/clippy_lints/src/utils/sym.rs
new file mode 100644 (file)
index 0000000..263d2d4
--- /dev/null
@@ -0,0 +1,393 @@
+#![allow(default_hash_types, non_upper_case_globals)]
+
+use lazy_static::lazy_static;
+use syntax::symbol::Symbol;
+
+macro_rules! symbols_simple {
+    ($($ident:ident,)*) => {
+        $(
+            lazy_static! {
+                pub(crate) static ref $ident: Symbol = Symbol::intern(stringify!($ident));
+            }
+        )*
+    };
+}
+
+macro_rules! symbols_init {
+    ($($ident:ident: $expr:expr,)*) => {
+        $(
+            lazy_static! {
+                pub(crate) static ref $ident: Symbol = Symbol::intern($expr);
+            }
+        )*
+    };
+}
+
+// exists because concat_idents is flaky
+pub mod assign {
+    pub(crate) use super::AddAssign as Add;
+    pub(crate) use super::AndAssign as And;
+    pub(crate) use super::BitAndAssign as BitAnd;
+    pub(crate) use super::BitOrAssign as BitOr;
+    pub(crate) use super::BitXorAssign as BitXor;
+    pub(crate) use super::DivAssign as Div;
+    pub(crate) use super::MulAssign as Mul;
+    pub(crate) use super::OrAssign as Or;
+    pub(crate) use super::RemAssign as Rem;
+    pub(crate) use super::ShlAssign as Shl;
+    pub(crate) use super::ShrAssign as Shr;
+    pub(crate) use super::SubAssign as Sub;
+}
+
+symbols_simple! {
+    Option,
+    rustc,
+    AsMut,
+    AsRef,
+    Clone,
+    Default,
+    DoubleEndedIterator,
+    Drop,
+    From,
+    Into,
+    IntoIterator,
+    Iterator,
+    Ord,
+    PartialOrd,
+    Any,
+    add,
+    Add,
+    AddAssign,
+    AndAssign,
+    OrAssign,
+    all,
+    alloc,
+    always,
+    any,
+    Arc,
+    Arguments,
+    array,
+    as_bytes,
+    as_mut,
+    as_ref,
+    assert,
+    as_str,
+    automatically_derived,
+    begin_panic,
+    begin_panic_fmt,
+    binary_heap,
+    BinaryHeap,
+    bitand,
+    BitAndAssign,
+    bitor,
+    BitOrAssign,
+    bitxor,
+    BitXorAssign,
+    bool,
+    borrow,
+    Borrow,
+    borrow_mut,
+    btree,
+    BTreeMap,
+    BTreeSet,
+    by_ref,
+    bytes,
+    capacity,
+    cfg,
+    cfg_attr,
+    chain,
+    chars,
+    clone,
+    cloned,
+    cmp,
+    collect,
+    collections,
+    conf_file,
+    contains,
+    contains_key,
+    context,
+    convert,
+    core,
+    count,
+    Cow,
+    c_str,
+    CString,
+    cycle,
+    dbg,
+    de,
+    debug_assert,
+    default,
+    deprecated,
+    deref,
+    Deref,
+    deref_mut,
+    discriminant,
+    Display,
+    div,
+    Div,
+    DivAssign,
+    doc,
+    drop,
+    Duration,
+    E,
+    EarlyContext,
+    end,
+    ends_with,
+    Entry,
+    enumerate,
+    eq,
+    Err,
+    extend,
+    ffi,
+    filter,
+    filter_map,
+    find,
+    flat_map,
+    fmt,
+    fold,
+    for_each,
+    forget,
+    format,
+    FRAC_1_PI,
+    FRAC_1_SQRT_2,
+    FRAC_2_PI,
+    FRAC_2_SQRT_PI,
+    FRAC_PI_2,
+    FRAC_PI_3,
+    FRAC_PI_4,
+    FRAC_PI_6,
+    FRAC_PI_8,
+    from,
+    from_elem,
+    from_iter,
+    from_str,
+    fs,
+    fuse,
+    hash,
+    Hash,
+    HashMap,
+    HashSet,
+    hidden,
+    i128,
+    i16,
+    i32,
+    i64,
+    i8,
+    Implied,
+    index,
+    Index,
+    index_mut,
+    IndexMut,
+    init,
+    inline,
+    insert,
+    inspect,
+    into_iter,
+    into_result,
+    into_vec,
+    intrinsics,
+    io,
+    is_empty,
+    is_err,
+    isize,
+    is_none,
+    is_ok,
+    is_some,
+    iter,
+    Iter,
+    iterator,
+    iter_mut,
+    last,
+    LateContext,
+    len,
+    linked_list,
+    LinkedList,
+    lint,
+    Lint,
+    LintPass,
+    LN_10,
+    LN_2,
+    LOG10_E,
+    LOG2_E,
+    macro_use,
+    main,
+    map,
+    matches,
+    match_indices,
+    max,
+    MAX,
+    max_by,
+    max_by_key,
+    mem,
+    min,
+    MIN,
+    min_by,
+    min_by_key,
+    mpsc,
+    mul,
+    Mul,
+    MulAssign,
+    mutex,
+    Mutex,
+    NAN,
+    ne,
+    neg,
+    new,
+    new_v1,
+    new_v1_formatted,
+    next,
+    next_back,
+    None,
+    not,
+    null,
+    null_mut,
+    offset,
+    ok,
+    Ok,
+    ONCE_INIT,
+    open,
+    OpenOptions,
+    ops,
+    option,
+    os_str,
+    OsStr,
+    OsString,
+    panic,
+    panicking,
+    partition,
+    path,
+    Path,
+    PathBuf,
+    paths,
+    peekable,
+    PI,
+    position,
+    precision,
+    print,
+    println,
+    proc_macro,
+    proc_macro_attribute,
+    proc_macro_derive,
+    product,
+    ptr,
+    push,
+    Range,
+    RangeBounds,
+    RangeFrom,
+    RangeFull,
+    RangeInclusive,
+    RangeTo,
+    RangeToInclusive,
+    rc,
+    Rc,
+    Read,
+    re_builder,
+    re_bytes,
+    Receiver,
+    regex,
+    Regex,
+    RegexBuilder,
+    RegexSet,
+    rem,
+    RemAssign,
+    repeat,
+    replace,
+    re_set,
+    resize,
+    result,
+    Result,
+    re_unicode,
+    rev,
+    rfind,
+    rmatches,
+    rmatch_indices,
+    rplit_terminator,
+    rposition,
+    rsplit,
+    rsplitn,
+    rsplit_terminator,
+    rustfmt,
+    rustfmt_skip,
+    scan,
+    serde,
+    set,
+    shl,
+    ShlAssign,
+    shr,
+    ShrAssign,
+    since,
+    skip,
+    skip_while,
+    slice,
+    Some,
+    split,
+    splitn,
+    split_terminator,
+    SQRT_2,
+    start,
+    starts_with,
+    std,
+    stderr,
+    stdin,
+    stdio,
+    stdout,
+    string,
+    String,
+    sub,
+    Sub,
+    SubAssign,
+    sum,
+    sync,
+    take,
+    take_while,
+    test,
+    time,
+    to_os_string,
+    to_owned,
+    ToOwned,
+    to_path_buf,
+    to_string,
+    ToString,
+    traits,
+    transmute,
+    trim_end_matches,
+    trim_start_matches,
+    Try,
+    u128,
+    u16,
+    u32,
+    u64,
+    u8,
+    unicode,
+    unimplemented,
+    uninit,
+    uninitialized,
+    unreachable,
+    unused_extern_crates,
+    unused_imports,
+    unwrap,
+    unwrap_err,
+    unzip,
+    usize,
+    utils,
+    vec,
+    Vec,
+    vec_deque,
+    VecDeque,
+    Visitor,
+    Weak,
+    width,
+    with_capacity,
+    wrapping_offset,
+    write,
+    Write,
+    write_fmt,
+    writeln,
+    zeroed,
+    zip,
+}
+
+symbols_init! {
+    impl_slice_t: "<impl [T]>",
+    empty_symbol: "",
+}
index 43e492bfb4e40f70b6fe7a4d1f796deeb6538b70..4e66da8b19f42e331caa0fcfaa8dfb8b04a968a4 100644 (file)
@@ -1,19 +1,17 @@
-use rustc::lint::*;
-
-use rustc::hir::def::Def;
+use rustc::hir::def::Res;
 use rustc::hir::*;
+use rustc::lint::LateContext;
 use rustc::middle::expr_use_visitor::*;
 use rustc::middle::mem_categorization::cmt_;
 use rustc::middle::mem_categorization::Categorization;
 use rustc::ty;
-use std::collections::HashSet;
-use syntax::ast::NodeId;
-use syntax::codemap::Span;
+use rustc_data_structures::fx::FxHashSet;
+use syntax::source_map::Span;
 
-/// Returns a set of mutated local variable ids or None if mutations could not be determined.
-pub fn mutated_variables<'a, 'tcx: 'a>(expr: &'tcx Expr, cx: &'a LateContext<'a, 'tcx>) -> Option<HashSet<NodeId>> {
+/// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
+pub fn mutated_variables<'a, 'tcx: 'a>(expr: &'tcx Expr, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> {
     let mut delegate = MutVarsDelegate {
-        used_mutably: HashSet::new(),
+        used_mutably: FxHashSet::default(),
         skip: false,
     };
     let def_id = def_id::DefId::local(expr.hir_id.owner);
@@ -31,19 +29,20 @@ pub fn is_potentially_mutated<'a, 'tcx: 'a>(
     expr: &'tcx Expr,
     cx: &'a LateContext<'a, 'tcx>,
 ) -> bool {
-    let id = match variable.def {
-        Def::Local(id) | Def::Upvar(id, ..) => id,
+    let id = match variable.res {
+        Res::Local(id) | Res::Upvar(id, ..) => id,
         _ => return true,
     };
     mutated_variables(expr, cx).map_or(true, |mutated| mutated.contains(&id))
 }
 
 struct MutVarsDelegate {
-    used_mutably: HashSet<NodeId>,
+    used_mutably: FxHashSet<HirId>,
     skip: bool,
 }
 
 impl<'tcx> MutVarsDelegate {
+    #[allow(clippy::similar_names)]
     fn update(&mut self, cat: &'tcx Categorization<'_>) {
         match *cat {
             Categorization::Local(id) => {
@@ -62,21 +61,21 @@ fn update(&mut self, cat: &'tcx Categorization<'_>) {
 }
 
 impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
-    fn consume(&mut self, _: NodeId, _: Span, _: &cmt_<'tcx>, _: ConsumeMode) {}
+    fn consume(&mut self, _: HirId, _: Span, _: &cmt_<'tcx>, _: ConsumeMode) {}
 
     fn matched_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: MatchMode) {}
 
     fn consume_pat(&mut self, _: &Pat, _: &cmt_<'tcx>, _: ConsumeMode) {}
 
-    fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, bk: ty::BorrowKind, _: LoanCause) {
+    fn borrow(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, bk: ty::BorrowKind, _: LoanCause) {
         if let ty::BorrowKind::MutBorrow = bk {
             self.update(&cmt.cat)
         }
     }
 
-    fn mutate(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: MutateMode) {
+    fn mutate(&mut self, _: HirId, _: Span, cmt: &cmt_<'tcx>, _: MutateMode) {
         self.update(&cmt.cat)
     }
 
-    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
+    fn decl_without_init(&mut self, _: HirId, _: Span) {}
 }
index cea3307a8273fcc0280da7da664879b64ee3cf88..2422a7060cd1a4beeebf7604a0e5b7c64805b54c 100644 (file)
@@ -1,44 +1,38 @@
-use rustc::hir::*;
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::consts::constant;
+use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg};
 use if_chain::if_chain;
+use rustc::hir::*;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty::{self, Ty};
-use syntax::codemap::Span;
-use crate::utils::{higher, is_copy, snippet, span_lint_and_sugg};
-use crate::consts::constant;
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax::source_map::Span;
 
-/// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
-/// be possible.
-///
-/// **Why is this bad?** This is less efficient.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// foo(&vec![1, 2])
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
+    /// be possible.
+    ///
+    /// **Why is this bad?** This is less efficient.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// foo(&vec![1, 2])
+    /// ```
     pub USELESS_VEC,
     perf,
     "useless `vec!`"
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(USELESS_VEC)
-    }
-}
+declare_lint_pass!(UselessVec => [USELESS_VEC]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessVec {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         // search for `&vec![_]` expressions where the adjusted type is `&[_]`
         if_chain! {
-            if let ty::TyRef(_, ty, _) = cx.tables.expr_ty_adjusted(expr).sty;
-            if let ty::TySlice(..) = ty.sty;
+            if let ty::Ref(_, ty, _) = cx.tables.expr_ty_adjusted(expr).sty;
+            if let ty::Slice(..) = ty.sty;
             if let ExprKind::AddrOf(_, ref addressee) = expr.node;
             if let Some(vec_args) = higher::vec_macro(cx, addressee);
             then {
@@ -54,6 +48,11 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             then {
                 // report the error around the `vec!` not inside `<std macros>:`
                 let span = arg.span
+                    .ctxt()
+                    .outer()
+                    .expn_info()
+                    .map(|info| info.call_site)
+                    .expect("unable to get call_site")
                     .ctxt()
                     .outer()
                     .expn_info()
@@ -66,20 +65,27 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
 }
 
 fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) {
+    let mut applicability = Applicability::MachineApplicable;
     let snippet = match *vec_args {
         higher::VecArgs::Repeat(elem, len) => {
             if constant(cx, cx.tables, len).is_some() {
-                format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len"))
+                format!(
+                    "&[{}; {}]",
+                    snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
+                    snippet_with_applicability(cx, len.span, "len", &mut applicability)
+                )
             } else {
                 return;
             }
         },
-        higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() {
-            let span = args[0].span.to(last.span);
+        higher::VecArgs::Vec(args) => {
+            if let Some(last) = args.iter().last() {
+                let span = args[0].span.to(last.span);
 
-            format!("&[{}]", snippet(cx, span, ".."))
-        } else {
-            "&[]".into()
+                format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
+            } else {
+                "&[]".into()
+            }
         },
     };
 
@@ -90,12 +96,13 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA
         "useless use of `vec!`",
         "you can use a slice directly",
         snippet,
+        applicability,
     );
 }
 
-/// Return the item type of the vector (ie. the `T` in `Vec<T>`).
+/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
 fn vec_type(ty: Ty<'_>) -> Ty<'_> {
-    if let ty::TyAdt(_, substs) = ty.sty {
+    if let ty::Adt(_, substs) = ty.sty {
         substs.type_at(0)
     } else {
         panic!("The type of `vec!` is a not a struct?");
diff --git a/clippy_lints/src/wildcard_dependencies.rs b/clippy_lints/src/wildcard_dependencies.rs
new file mode 100644 (file)
index 0000000..b2a66b6
--- /dev/null
@@ -0,0 +1,59 @@
+use crate::utils::span_lint;
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use syntax::{ast::*, source_map::DUMMY_SP};
+
+use cargo_metadata;
+use if_chain::if_chain;
+use semver;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for wildcard dependencies in the `Cargo.toml`.
+    ///
+    /// **Why is this bad?** [As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html),
+    /// it is highly unlikely that you work with any possible version of your dependency,
+    /// and wildcard dependencies would cause unnecessary breakage in the ecosystem.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```toml
+    /// [dependencies]
+    /// regex = "*"
+    /// ```
+    pub WILDCARD_DEPENDENCIES,
+    cargo,
+    "wildcard dependencies being used"
+}
+
+declare_lint_pass!(WildcardDependencies => [WILDCARD_DEPENDENCIES]);
+
+impl EarlyLintPass for WildcardDependencies {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
+        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
+            metadata
+        } else {
+            span_lint(cx, WILDCARD_DEPENDENCIES, DUMMY_SP, "could not read cargo metadata");
+            return;
+        };
+
+        for dep in &metadata.packages[0].dependencies {
+            // VersionReq::any() does not work
+            if_chain! {
+                if let Ok(wildcard_ver) = semver::VersionReq::parse("*");
+                if let Some(ref source) = dep.source;
+                if !source.starts_with("git");
+                if dep.req == wildcard_ver;
+                then {
+                    span_lint(
+                        cx,
+                        WILDCARD_DEPENDENCIES,
+                        DUMMY_SP,
+                        &format!("wildcard dependency for `{}`", dep.name),
+                    );
+                }
+            }
+        }
+    }
+}
index 0b52981bfa584ab2a28d8233018154808062f36a..5c9fc943492c43d83f4a2b0270bf76faba03e828 100644 (file)
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, sym};
+use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use std::borrow::Cow;
 use syntax::ast::*;
-use syntax::tokenstream::{ThinTokenStream, TokenStream};
-use syntax::parse::{token, parser};
-use crate::utils::{span_lint, span_lint_and_sugg};
+use syntax::parse::{parser, token};
+use syntax::symbol::Symbol;
+use syntax::tokenstream::{TokenStream, TokenTree};
 
-/// **What it does:** This lint warns when you use `println!("")` to
-/// print a newline.
-///
-/// **Why is this bad?** You should use `println!()`, which is simpler.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// println!("");
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint warns when you use `println!("")` to
+    /// print a newline.
+    ///
+    /// **Why is this bad?** You should use `println!()`, which is simpler.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// println!("");
+    /// ```
     pub PRINTLN_EMPTY_STRING,
     style,
     "using `println!(\"\")` with an empty string"
 }
 
-/// **What it does:** This lint warns when you use `print!()` with a format
-/// string that
-/// ends in a newline.
-///
-/// **Why is this bad?** You should use `println!()` instead, which appends the
-/// newline.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// print!("Hello {}!\n", name);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint warns when you use `print!()` with a format
+    /// string that
+    /// ends in a newline.
+    ///
+    /// **Why is this bad?** You should use `println!()` instead, which appends the
+    /// newline.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let name = "World";
+    /// print!("Hello {}!\n", name);
+    /// ```
+    /// use println!() instead
+    /// ```rust
+    /// # let name = "World";
+    /// println!("Hello {}!", name);
+    /// ```
     pub PRINT_WITH_NEWLINE,
     style,
-    "using `print!()` with a format string that ends in a newline"
+    "using `print!()` with a format string that ends in a single newline"
 }
 
-/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
-/// is to catch debugging remnants.
-///
-/// **Why is this bad?** People often print on *stdout* while debugging an
-/// application and might forget to remove those prints afterward.
-///
-/// **Known problems:** Only catches `print!` and `println!` calls.
-///
-/// **Example:**
-/// ```rust
-/// println!("Hello world!");
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for printing on *stdout*. The purpose of this lint
+    /// is to catch debugging remnants.
+    ///
+    /// **Why is this bad?** People often print on *stdout* while debugging an
+    /// application and might forget to remove those prints afterward.
+    ///
+    /// **Known problems:** Only catches `print!` and `println!` calls.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// println!("Hello world!");
+    /// ```
     pub PRINT_STDOUT,
     restriction,
     "printing on stdout"
 }
 
-/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
-/// lint is to catch debugging remnants.
-///
-/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
-/// debugging Rust code. It should not be used in in user-facing output.
-///
-/// **Example:**
-/// ```rust
-/// println!("{:?}", foo);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for use of `Debug` formatting. The purpose of this
+    /// lint is to catch debugging remnants.
+    ///
+    /// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
+    /// debugging Rust code. It should not be used in in user-facing output.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// println!("{:?}", foo);
+    /// ```
     pub USE_DEBUG,
     restriction,
     "use of `Debug`-based formatting"
 }
 
-/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
-///
-/// **Why is this bad?** Using literals as `println!` args is inefficient
-/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
-/// (i.e., just put the literal in the format string)
-///
-/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
-/// -- e.g., `println!("{}", env!("FOO"))`.
-///
-/// **Example:**
-/// ```rust
-/// println!("{}", "foo");
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
+    ///
+    /// **Why is this bad?** Using literals as `println!` args is inefficient
+    /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+    /// (i.e., just put the literal in the format string)
+    ///
+    /// **Known problems:** Will also warn with macro calls as arguments that expand to literals
+    /// -- e.g., `println!("{}", env!("FOO"))`.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// println!("{}", "foo");
+    /// ```
+    /// use the literal without formatting:
+    /// ```rust
+    /// println!("foo");
+    /// ```
     pub PRINT_LITERAL,
     style,
     "printing a literal with a format string"
 }
 
-/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
-/// print a newline.
-///
-/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// writeln!("");
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint warns when you use `writeln!(buf, "")` to
+    /// print a newline.
+    ///
+    /// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use std::fmt::Write;
+    /// # let mut buf = String::new();
+    /// writeln!(buf, "");
+    /// ```
     pub WRITELN_EMPTY_STRING,
     style,
-    "using `writeln!(\"\")` with an empty string"
+    "using `writeln!(buf, \"\")` with an empty string"
 }
 
-/// **What it does:** This lint warns when you use `write!()` with a format
-/// string that
-/// ends in a newline.
-///
-/// **Why is this bad?** You should use `writeln!()` instead, which appends the
-/// newline.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// write!(buf, "Hello {}!\n", name);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint warns when you use `write!()` with a format
+    /// string that
+    /// ends in a newline.
+    ///
+    /// **Why is this bad?** You should use `writeln!()` instead, which appends the
+    /// newline.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use std::fmt::Write;
+    /// # let mut buf = String::new();
+    /// # let name = "World";
+    /// write!(buf, "Hello {}!\n", name);
+    /// ```
     pub WRITE_WITH_NEWLINE,
     style,
-    "using `write!()` with a format string that ends in a newline"
+    "using `write!()` with a format string that ends in a single newline"
 }
 
-/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
-///
-/// **Why is this bad?** Using literals as `writeln!` args is inefficient
-/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
-/// (i.e., just put the literal in the format string)
-///
-/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
-/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
-///
-/// **Example:**
-/// ```rust
-/// writeln!(buf, "{}", "foo");
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
+    ///
+    /// **Why is this bad?** Using literals as `writeln!` args is inefficient
+    /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+    /// (i.e., just put the literal in the format string)
+    ///
+    /// **Known problems:** Will also warn with macro calls as arguments that expand to literals
+    /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # use std::fmt::Write;
+    /// # let mut buf = String::new();
+    /// writeln!(buf, "{}", "foo");
+    /// ```
     pub WRITE_LITERAL,
     style,
     "writing a literal with a format string"
 }
 
-#[derive(Copy, Clone, Debug)]
-pub struct Pass;
+declare_lint_pass!(Write => [
+    PRINT_WITH_NEWLINE,
+    PRINTLN_EMPTY_STRING,
+    PRINT_STDOUT,
+    USE_DEBUG,
+    PRINT_LITERAL,
+    WRITE_WITH_NEWLINE,
+    WRITELN_EMPTY_STRING,
+    WRITE_LITERAL
+]);
 
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            PRINT_WITH_NEWLINE,
-            PRINTLN_EMPTY_STRING,
-            PRINT_STDOUT,
-            USE_DEBUG,
-            PRINT_LITERAL,
-            WRITE_WITH_NEWLINE,
-            WRITELN_EMPTY_STRING,
-            WRITE_LITERAL
-        )
-    }
-}
-
-impl EarlyLintPass for Pass {
+impl EarlyLintPass for Write {
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
-        if mac.node.path == "println" {
+        if mac.node.path == *sym::println {
             span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
-            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) {
+            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                 if fmtstr == "" {
                     span_lint_and_sugg(
                         cx,
@@ -180,36 +193,56 @@ fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
                         "using `println!(\"\")`",
                         "replace it with",
                         "println!()".to_string(),
+                        Applicability::MachineApplicable,
                     );
                 }
             }
-        } else if mac.node.path == "print" {
+        } else if mac.node.path == *sym::print {
             span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
-            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false) {
-                if fmtstr.ends_with("\\n") {
-                    span_lint(cx, PRINT_WITH_NEWLINE, mac.span,
-                            "using `print!()` with a format string that ends in a \
-                            newline, consider using `println!()` instead");
+            if let (Some(fmtstr), _, is_raw) = check_tts(cx, &mac.node.tts, false) {
+                if check_newlines(&fmtstr, is_raw) {
+                    span_lint(
+                        cx,
+                        PRINT_WITH_NEWLINE,
+                        mac.span,
+                        "using `print!()` with a format string that ends in a \
+                         single newline, consider using `println!()` instead",
+                    );
                 }
             }
-        } else if mac.node.path == "write" {
-            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) {
-                if fmtstr.ends_with("\\n") {
-                    span_lint(cx, WRITE_WITH_NEWLINE, mac.span,
-                            "using `write!()` with a format string that ends in a \
-                            newline, consider using `writeln!()` instead");
+        } else if mac.node.path == *sym::write {
+            if let (Some(fmtstr), _, is_raw) = check_tts(cx, &mac.node.tts, true) {
+                if check_newlines(&fmtstr, is_raw) {
+                    span_lint(
+                        cx,
+                        WRITE_WITH_NEWLINE,
+                        mac.span,
+                        "using `write!()` with a format string that ends in a \
+                         single newline, consider using `writeln!()` instead",
+                    );
                 }
             }
-        } else if mac.node.path == "writeln" {
-            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true) {
+        } else if mac.node.path == *sym::writeln {
+            let check_tts = check_tts(cx, &mac.node.tts, true);
+            if let Some(fmtstr) = check_tts.0 {
                 if fmtstr == "" {
+                    let mut applicability = Applicability::MachineApplicable;
+                    let suggestion = check_tts.1.map_or_else(
+                        move || {
+                            applicability = Applicability::HasPlaceholders;
+                            Cow::Borrowed("v")
+                        },
+                        move |expr| snippet_with_applicability(cx, expr.span, "v", &mut applicability),
+                    );
+
                     span_lint_and_sugg(
                         cx,
                         WRITELN_EMPTY_STRING,
                         mac.span,
-                        "using `writeln!(v, \"\")`",
+                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
                         "replace it with",
-                        "writeln!(v)".to_string(),
+                        format!("writeln!({})", suggestion),
+                        applicability,
                     );
                 }
             }
@@ -217,29 +250,65 @@ fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
     }
 }
 
-fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Option<String> {
-    let tts = TokenStream::from(tts.clone());
-    let mut parser = parser::Parser::new(
-        &cx.sess.parse_sess,
-        tts,
-        None,
-        false,
-        false,
-    );
+/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
+/// options and a bool. The first part of the tuple is `format_str` of the macros. The second part
+/// of the tuple is in the `write[ln]!` case the expression the `format_str` should be written to.
+/// The final part is a boolean flag indicating if the string is a raw string.
+///
+/// Example:
+///
+/// Calling this function on
+/// ```rust
+/// # use std::fmt::Write;
+/// # let mut buf = String::new();
+/// # let something = "something";
+/// writeln!(buf, "string to write: {}", something);
+/// ```
+/// will return
+/// ```rust,ignore
+/// (Some("string to write: {}"), Some(buf), false)
+/// ```
+fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &TokenStream, is_write: bool) -> (Option<String>, Option<Expr>, bool) {
+    use fmt_macros::*;
+    let tts = tts.clone();
+    let mut is_raw = false;
+    if let TokenStream(Some(tokens)) = &tts {
+        for token in tokens.iter() {
+            if let (TokenTree::Token(_, token::Token::Literal(lit, _)), _) = token {
+                match lit {
+                    token::Lit::Str_(_) => break,
+                    token::Lit::StrRaw(_, _) => {
+                        is_raw = true;
+                        break;
+                    },
+                    _ => {},
+                }
+            }
+        }
+    }
+    let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false);
+    let mut expr: Option<Expr> = None;
     if is_write {
-        // skip the initial write target
-        parser.parse_expr().map_err(|mut err| err.cancel()).ok()?;
+        expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
+            Ok(p) => Some(p.into_inner()),
+            Err(_) => return (None, None, is_raw),
+        };
         // might be `writeln!(foo)`
-        parser.expect(&token::Comma).map_err(|mut err| err.cancel()).ok()?;
+        if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
+            return (None, expr, is_raw);
+        }
     }
-    let fmtstr = parser.parse_str().map_err(|mut err| err.cancel()).ok()?.0.to_string();
-    use fmt_macros::*;
+
+    let fmtstr = match parser.parse_str().map_err(|mut err| err.cancel()) {
+        Ok(token) => token.0.to_string(),
+        Err(_) => return (None, expr, is_raw),
+    };
     let tmp = fmtstr.clone();
     let mut args = vec![];
-    let mut fmt_parser = Parser::new(&tmp, None);
+    let mut fmt_parser = Parser::new(&tmp, None, Vec::new(), false);
     while let Some(piece) = fmt_parser.next() {
         if !fmt_parser.errors.is_empty() {
-            return None;
+            return (None, expr, is_raw);
         }
         if let Piece::NextArgument(arg) = piece {
             if arg.format.ty == "?" {
@@ -249,18 +318,9 @@ fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Op
             args.push(arg);
         }
     }
-    let lint = if is_write {
-        WRITE_LITERAL
-    } else {
-        PRINT_LITERAL
-    };
+    let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
     let mut idx = 0;
     loop {
-        if !parser.eat(&token::Comma) {
-            assert!(parser.eat(&token::Eof));
-            return Some(fmtstr);
-        }
-        let expr = parser.parse_expr().map_err(|mut err| err.cancel()).ok()?;
         const SIMPLE: FormatSpec<'_> = FormatSpec {
             fill: None,
             align: AlignUnknown,
@@ -269,23 +329,30 @@ fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Op
             width: CountImplied,
             ty: "",
         };
-        match &expr.node {
+        if !parser.eat(&token::Comma) {
+            return (Some(fmtstr), expr, is_raw);
+        }
+        let token_expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
+            Ok(expr) => expr,
+            Err(_) => return (Some(fmtstr), None, is_raw),
+        };
+        match &token_expr.node {
             ExprKind::Lit(_) => {
                 let mut all_simple = true;
                 let mut seen = false;
                 for arg in &args {
                     match arg.position {
-                        | ArgumentImplicitlyIs(n)
-                        | ArgumentIs(n)
-                        => if n == idx {
-                            all_simple &= arg.format == SIMPLE;
-                            seen = true;
+                        ArgumentImplicitlyIs(n) | ArgumentIs(n) => {
+                            if n == idx {
+                                all_simple &= arg.format == SIMPLE;
+                                seen = true;
+                            }
                         },
                         ArgumentNamed(_) => {},
                     }
                 }
                 if all_simple && seen {
-                    span_lint(cx, lint, expr.span, "literal with an empty format string");
+                    span_lint(cx, lint, token_expr.span, "literal with an empty format string");
                 }
                 idx += 1;
             },
@@ -296,12 +363,14 @@ fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Op
                         let mut seen = false;
                         for arg in &args {
                             match arg.position {
-                                | ArgumentImplicitlyIs(_)
-                                | ArgumentIs(_)
-                                => {},
-                                ArgumentNamed(name) => if *p == name {
-                                    seen = true;
-                                    all_simple &= arg.format == SIMPLE;
+                                ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
+                                ArgumentNamed(name) => {
+                                    // FIXME: remove this interning if possible
+                                    // https://github.com/rust-lang/rust/issues/60795
+                                    if *p == Symbol::intern(name) {
+                                        seen = true;
+                                        all_simple &= arg.format == SIMPLE;
+                                    }
                                 },
                             }
                         }
@@ -315,3 +384,36 @@ fn check_tts(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> Op
         }
     }
 }
+
+// Checks if `s` constains a single newline that terminates it
+// Literal and escaped newlines are both checked (only literal for raw strings)
+fn check_newlines(s: &str, is_raw: bool) -> bool {
+    if s.ends_with('\n') {
+        return true;
+    } else if is_raw {
+        return false;
+    }
+
+    if s.len() < 2 {
+        return false;
+    }
+
+    let bytes = s.as_bytes();
+    if bytes[bytes.len() - 2] != b'\\' || bytes[bytes.len() - 1] != b'n' {
+        return false;
+    }
+
+    let mut escaping = false;
+    for (index, &byte) in bytes.iter().enumerate() {
+        if escaping {
+            if byte == b'n' {
+                return index == bytes.len() - 1;
+            }
+            escaping = false;
+        } else if byte == b'\\' {
+            escaping = true;
+        }
+    }
+
+    false
+}
index 7c8af7880ba22b7ec5f7cdbfcc118f2ad1f32eb6..094cb627dc3a31c6c7fd5ae4ad9cb56bff6484ba 100644 (file)
@@ -1,36 +1,30 @@
 use crate::consts::{constant_simple, Constant};
-use rustc::lint::*;
-use rustc::{declare_lint, lint_array};
+use crate::utils::span_help_and_lint;
 use if_chain::if_chain;
 use rustc::hir::*;
-use crate::utils::span_help_and_lint;
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
 
-/// **What it does:** Checks for `0.0 / 0.0`.
-///
-/// **Why is this bad?** It's less readable than `std::f32::NAN` or
-/// `std::f64::NAN`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// 0.0f32 / 0.0
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `0.0 / 0.0`.
+    ///
+    /// **Why is this bad?** It's less readable than `std::f32::NAN` or
+    /// `std::f64::NAN`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// 0.0f32 / 0.0
+    /// ```
     pub ZERO_DIVIDED_BY_ZERO,
     complexity,
     "usage of `0.0 / 0.0` to obtain NaN instead of std::f32::NaN or std::f64::NaN"
 }
 
-pub struct Pass;
-
-impl LintPass for Pass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(ZERO_DIVIDED_BY_ZERO)
-    }
-}
+declare_lint_pass!(ZeroDiv => [ZERO_DIVIDED_BY_ZERO]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ZeroDiv {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         // check for instances of 0.0/0.0
         if_chain! {
index a282378c951c6f008ce19ab304936c4989ca7586..7a235b215d38d418b8ac0835f404706e72efc5f8 100644 (file)
@@ -1,6 +1,7 @@
 [package]
 name = "clippy_workspace_tests"
 version = "0.1.0"
+edition = "2018"
 
 [workspace]
 members = ["subcrate"]
index f79c691f0853c5b08e114041f7c8db43b0452fe0..0dcdf6383fd25a22783f7ab1e6d9d9c619b0aff4 100644 (file)
@@ -1,2 +1,4 @@
+#![deny(rust_2018_idioms)]
+
 fn main() {
 }
diff --git a/doc/adding_lints.md b/doc/adding_lints.md
new file mode 100644 (file)
index 0000000..a80ee9f
--- /dev/null
@@ -0,0 +1,429 @@
+## Adding a new lint
+
+You are probably here because you want to add a new lint to Clippy. If this is
+the first time you're contributing to Clippy, this document guides you through
+creating an example lint from scratch.
+
+To get started, we will create a lint that detects functions called `foo`,
+because that's clearly a non-descriptive name.
+
+* [Setup](#Setup)
+* [Testing](#Testing)
+* [Rustfix tests](#Rustfix-tests)
+* [Lint declaration](#Lint-declaration)
+* [Lint passes](#Lint-passes)
+* [Emitting a lint](#Emitting-a-lint)
+* [Adding the lint logic](#Adding-the-lint-logic)
+* [Author lint](#Author-lint)
+* [Documentation](#Documentation)
+* [Running rustfmt](#Running-rustfmt)
+* [Debugging](#Debugging)
+* [PR Checklist](#PR-Checklist)
+* [Cheatsheet](#Cheatsheet)
+
+### Setup
+
+When working on Clippy, you will need the current git master version of rustc,
+which can change rapidly. Make sure you're working near rust-clippy's master,
+and use the `setup-toolchain.sh` script to configure the appropriate toolchain
+for the Clippy directory.
+
+### Testing
+
+Let's write some tests first that we can execute while we iterate on our lint.
+
+Clippy uses UI tests for testing. UI tests check that the output of Clippy is
+exactly as expected. Each test is just a plain Rust file that contains the code
+we want to check. The output of Clippy is compared against a `.stderr` file.
+Note that you don't have to create this file yourself, we'll get to
+generating the `.stderr` files further down.
+
+We start by creating the test file at `tests/ui/foo_functions.rs`. It doesn't
+really matter what the file is called, but it's a good convention to name it
+after the lint it is testing, so `foo_functions.rs` it is.
+
+Inside the file we put some examples to get started:
+
+```rust
+#![warn(clippy::foo_functions)]
+
+// Impl methods
+struct A;
+impl A {
+    pub fn fo(&self) {}
+    pub fn foo(&self) {}
+    pub fn food(&self) {}
+}
+
+// Default trait methods
+trait B {
+    pub fn fo(&self) {}
+    pub fn foo(&self) {}
+    pub fn food(&self) {}
+}
+
+// Plain functions
+fn fo() {}
+fn foo() {}
+fn food() {}
+
+fn main() {
+    // We also don't want to lint method calls
+    foo();
+    let a = A;
+    a.foo();
+}
+
+```
+
+Now we can run the test with `TESTNAME=ui/foo_functions cargo uitest`.
+Currently this test will fail. If you go through the output you will see that we
+are told that `clippy::foo_functions` is an unknown lint, which is expected.
+
+While we are working on implementing our lint, we can keep running the UI
+test. That allows us to check if the output is turning into what we want.
+
+Once we are satisfied with the output, we need to run
+`tests/ui/update-all-references.sh` to update the `.stderr` file for our lint.
+Running `TESTNAME=ui/foo_functions cargo uitest` should pass then. When we
+commit our lint, we need to commit the generated `.stderr` files, too.
+
+### Rustfix tests
+
+If the lint you are working on is making use of structured suggestions, the
+test file should include a `// run-rustfix` comment at the top. This will
+additionally run [rustfix](https://github.com/rust-lang-nursery/rustfix) for
+that test. Rustfix will apply the suggestions from the lint to the code of the
+test file and compare that to the contents of a `.fixed` file.
+
+Use `tests/ui/update-all-references.sh` to automatically generate the
+`.fixed` file after running the tests.
+
+With tests in place, let's have a look at implementing our lint now.
+
+### Testing manually
+
+Manually testing against an example file can be useful if you have added some
+`println!`s and the test suite output becomes unreadable. To try Clippy with
+your local modifications, run `env CLIPPY_TESTS=true cargo run --bin
+clippy-driver -- -L ./target/debug input.rs` from the working copy root.
+
+### Lint declaration
+
+We start by creating a new file in the `clippy_lints` crate. That's the crate
+where all the lint code is. We are going to call the file
+`clippy_lints/src/foo_functions.rs` and import some initial things we need:
+
+```rust
+use rustc::lint::{LintArray, LintPass, EarlyLintPass};
+use rustc::{declare_lint_pass, declare_tool_lint};
+```
+
+The next step is to provide a lint declaration. Lints are declared using the
+[`declare_clippy_lint!`][declare_clippy_lint] macro:
+
+```rust
+declare_clippy_lint! {
+    pub FOO_FUNCTIONS,
+    pedantic,
+    "function named `foo`, which is not a descriptive name"
+}
+```
+
+* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the [lint naming
+guidelines][lint_naming] here when naming your lint. In short, the name should
+state the thing that is being checked for and read well when used with
+`allow`/`warn`/`deny`.
+* `pedantic` sets the lint level to `Allow`.
+  The exact mapping can be found [here][category_level_mapping]
+* The last part should be a text that explains what exactly is wrong with the
+  code
+
+With our lint declaration done, we will now make sure that it is assigned to a
+lint pass:
+
+```rust
+// clippy_lints/src/foo_functions.rs
+
+// .. imports and lint declaration ..
+
+declare_lint_pass!(FooFunctions => [FOO_FUNCTIONS]);
+
+impl EarlyLintPass for FooFunctions {}
+```
+
+Don't worry about the `name` method here. As long as it includes the name of the
+lint pass it should be fine.
+
+Next we need to run `util/dev update_lints` to register the lint in various
+places, mainly in `clippy_lints/src/lib.rs`.
+
+While `update_lints` automates some things, it doesn't automate everything. We
+will have to register our lint pass manually in the `register_plugins` function
+in `clippy_lints/src/lib.rs`:
+
+```rust
+reg.register_early_lint_pass(box foo_functions::FooFunctions);
+```
+
+This should fix the `unknown clippy lint: clippy::foo_functions` error that we
+saw when we executed our tests the first time. The next decision we have to make
+is which lint pass our lint is going to need.
+
+### Lint passes
+
+Writing a lint that only checks for the name of a function means that we only
+have to deal with the AST and don't have to deal with the type system at all.
+This is good, because it makes writing this particular lint less complicated.
+
+We have to make this decision with every new Clippy lint. It boils down to using
+either [`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass].
+
+In short, the `LateLintPass` has access to type information while the
+`EarlyLintPass` doesn't. If you don't need access to type information, use the
+`EarlyLintPass`. The `EarlyLintPass` is also faster. However linting speed
+hasn't really been a concern with Clippy so far.
+
+Since we don't need type information for checking the function name, we are
+going to use the `EarlyLintPass`. It has to be imported as well, changing our
+imports to:
+
+```rust
+use rustc::lint::{LintArray, LintPass, EarlyLintPass, EarlyContext};
+use rustc::{declare_tool_lint, lint_array};
+```
+
+### Emitting a lint
+
+With UI tests and the lint declaration in place, we can start working on the
+implementation of the lint logic.
+
+Let's start by implementing the `EarlyLintPass` for our `FooFunctions`:
+
+```rust
+impl EarlyLintPass for FooFunctions {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
+        // TODO: Emit lint here
+    }
+}
+```
+
+We implement the [`check_fn`][check_fn] method from the
+[`EarlyLintPass`][early_lint_pass] trait. This gives us access to various
+information about the function that is currently being checked. More on that in
+the next section. Let's worry about the details later and emit our lint for
+*every* function definition first.
+
+Depending on how complex we want our lint message to be, we can choose from a
+variety of lint emission functions. They can all be found in
+[`clippy_lints/src/utils/diagnostics.rs`][diagnostics].
+
+`span_help_and_lint` seems most appropriate in this case. It allows us to
+provide an extra help message and we can't really suggest a better name
+automatically. This is how it looks:
+
+```rust
+impl EarlyLintPass for FooFunctions {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, _: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
+        span_help_and_lint(
+            cx,
+            FOO_FUNCTIONS,
+            span,
+            "function named `foo`",
+            "consider using a more meaningful name"
+        );
+    }
+}
+```
+
+Running our UI test should now produce output that contains the lint message.
+
+### Adding the lint logic
+
+Writing the logic for your lint will most likely be different from our example,
+so this section is kept rather short.
+
+Using the [`check_fn`][check_fn] method gives us access to [`FnKind`][fn_kind]
+that has two relevant variants for us `FnKind::ItemFn` and `FnKind::Method`.
+Both provide access to the name of the function/method via an [`Ident`][ident].
+
+With that we can expand our `check_fn` method to:
+
+```rust
+impl EarlyLintPass for FooFunctions {
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: &FnDecl, span: Span, _: NodeId) {
+        if is_foo_fn(fn_kind) {
+            span_help_and_lint(
+                cx,
+                FOO_FUNCTIONS,
+                span,
+                "function named `foo`",
+                "consider using a more meaningful name"
+            );
+        }
+    }
+}
+```
+
+We separate the lint conditional from the lint emissions because it makes the
+code a bit easier to read. In some cases this separation would also allow to
+write some unit tests (as opposed to only UI tests) for the separate function.
+
+In our example, `is_foo_fn` looks like:
+
+```rust
+// use statements, impl EarlyLintPass, check_fn, ..
+
+fn is_foo_fn(fn_kind: FnKind<'_>) -> bool {
+    match fn_kind {
+        FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) => {
+            ident.name == "foo"
+        },
+        FnKind::Closure(..) => false
+    }
+}
+```
+
+Now we should also run the full test suite with `cargo test`. At this point
+running `cargo test` should produce the expected output. Remember to run
+`tests/ui/update-all-references.sh` to update the `.stderr` file.
+
+`cargo test` (as opposed to `cargo uitest`) will also ensure that our lint
+implementation is not violating any Clippy lints itself.
+
+That should be it for the lint implementation. Running `cargo test` should now
+pass.
+
+### Author lint
+
+If you have trouble implementing your lint, there is also the internal `author`
+lint to generate Clippy code that detects the offending pattern. It does not
+work for all of the Rust syntax, but can give a good starting point.
+
+The quickest way to use it, is the [Rust playground][play].rust-lang.org).
+Put the code you want to lint into the editor and add the `#[clippy::author]`
+attribute above the item. Then run Clippy via `Tools -> Clippy` and you should
+see the generated code in the output below.
+
+[Here][author_example] is an example on the playground.
+
+If the command was executed successfully, you can copy the code over to where
+you are implementing your lint.
+
+### Documentation
+
+The final thing before submitting our PR is to add some documentation to our
+lint declaration.
+
+Please document your lint with a doc comment akin to the following:
+
+```rust
+declare_clippy_lint! {
+    /// **What it does:** Checks for ... (describe what the lint matches).
+    ///
+    /// **Why is this bad?** Supply the reason for linting the code.
+    ///
+    /// **Known problems:** None. (Or describe where it could go wrong.)
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// // Bad
+    /// Insert a short example of code that triggers the lint
+    ///
+    /// // Good
+    /// Insert a short example of improved code that doesn't trigger the lint
+    /// ```
+    pub FOO_FUNCTIONS,
+    pedantic,
+    "function named `foo`, which is not a descriptive name"
+}
+```
+
+Once your lint is merged, this documentation will show up in the [lint
+list][lint_list].
+
+### Running rustfmt
+
+[Rustfmt](https://github.com/rust-lang/rustfmt) is a tool for formatting Rust code according
+to style guidelines. Your code has to be formatted by `rustfmt` before a PR can be merged.
+
+It can be installed via `rustup`:
+
+```bash
+rustup component add rustfmt
+```
+
+Use `cargo fmt --all` to format the whole codebase.
+
+### Debugging
+
+If you want to debug parts of your lint implementation, you can use the `dbg!`
+macro anywhere in your code. Running the tests should then include the debug
+output in the `stdout` part.
+
+### PR Checklist
+
+Before submitting your PR make sure you followed all of the basic requirements:
+
+- [ ] Followed [lint naming conventions][lint_naming]
+- [ ] Added passing UI tests (including committed `.stderr` file)
+- [ ] `cargo test` passes locally
+- [ ] Executed `util/dev update_lints`
+- [ ] Added lint documentation
+- [ ] Run `cargo fmt`
+
+### Cheatsheet
+
+Here are some pointers to things you are likely going to need for every lint:
+
+* [Clippy utils][utils] - Various helper functions. Maybe the function you need
+  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]
+* [`Span`][span]
+* [`Applicability`][applicability]
+* [The rustc guide][rustc_guide] explains a lot of internal compiler concepts
+* [The nightly rustc docs][nightly_docs] which has been linked to throughout
+  this guide
+
+For `EarlyLintPass` lints:
+
+* [`EarlyLintPass`][early_lint_pass]
+* [`syntax::ast`][ast]
+
+For `LateLintPass` lints:
+
+* [`LateLintPass`][late_lint_pass]
+* [`Ty::TyKind`][ty]
+
+
+While most of Clippy's lint utils are documented, most of rustc's internals lack
+documentation currently. This is unfortunate, but in most cases you can probably
+get away with copying things from existing similar lints. If you are stuck,
+don't hesitate to ask on Discord, IRC or in the issue/PR.
+
+[lint_list]: https://rust-lang.github.io/rust-clippy/master/index.html
+[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/bd23cb89ec0ea63403a17d3fc5e50c88e38dd54f/clippy_lints/src/lib.rs#L43
+[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/a71acac1da7eaf667ab90a1d65d10e5cc4b80191/clippy_lints/src/lib.rs#L39
+[compilation_stages]: https://rust-lang.github.io/rustc-guide/high-level-overview.html#the-main-stages-of-compilation
+[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/trait.EarlyLintPass.html#method.check_fn
+[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
+[fn_kind]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/visit/enum.FnKind.html
+[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
+[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
+[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/
+[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
+[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
+[rustc_guide]: https://rust-lang.github.io/rustc-guide/
+[nightly_docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/
diff --git a/etc/relicense/RELICENSE_DOCUMENTATION.md b/etc/relicense/RELICENSE_DOCUMENTATION.md
new file mode 100644 (file)
index 0000000..847e66e
--- /dev/null
@@ -0,0 +1,36 @@
+This repository was previously licensed under MPL-2.0, however in #3093 ([archive](http://web.archive.org/web/20181005185227/https://github.com/rust-lang-nursery/rust-clippy/issues/3093),  [screenshot](https://user-images.githubusercontent.com/1617736/46573505-5b856880-c94b-11e8-9a14-981c889b4981.png)) we relicensed it to the Rust license (dual licensed as Apache v2 / MIT)
+
+At the time, the contributors were those listed in contributors.txt.
+
+We opened a bunch of issues asking for an explicit relicensing approval. Screenshots of all these issues at the time of relicensing are archived on GitHub. We also have saved Wayback Machine copies of these:
+
+ - #3094 ([archive](http://web.archive.org/web/20181005191247/https://github.com/rust-lang-nursery/rust-clippy/issues/3094), [screenshot](https://user-images.githubusercontent.com/1617736/46573506-5b856880-c94b-11e8-8a44-51cb40bc16ee.png))
+ - #3095 ([archive](http://web.archive.org/web/20181005184416/https://github.com/rust-lang-nursery/rust-clippy/issues/3095), [screenshot](https://user-images.githubusercontent.com/1617736/46573507-5c1dff00-c94b-11e8-912a-4bd6b5f838f5.png))
+ - #3096 ([archive](http://web.archive.org/web/20181005184802/https://github.com/rust-lang-nursery/rust-clippy/issues/3096), [screenshot](https://user-images.githubusercontent.com/1617736/46573508-5c1dff00-c94b-11e8-9425-2464f7260ff0.png))
+ - #3097 ([archive](http://web.archive.org/web/20181005184821/https://github.com/rust-lang-nursery/rust-clippy/issues/3097), [screenshot](https://user-images.githubusercontent.com/1617736/46573509-5c1dff00-c94b-11e8-8ba2-53f687984fe7.png))
+ - #3098 ([archive](http://web.archive.org/web/20181005184900/https://github.com/rust-lang-nursery/rust-clippy/issues/3098), [screenshot](https://user-images.githubusercontent.com/1617736/46573510-5c1dff00-c94b-11e8-8f64-371698401c60.png))
+ - #3099 ([archive](http://web.archive.org/web/20181005184901/https://github.com/rust-lang-nursery/rust-clippy/issues/3099), [screenshot](https://user-images.githubusercontent.com/1617736/46573511-5c1dff00-c94b-11e8-8e20-7d0eeb392b95.png))
+ - #3100 ([archive](http://web.archive.org/web/20181005184901/https://github.com/rust-lang-nursery/rust-clippy/issues/3100), [screenshot](https://user-images.githubusercontent.com/1617736/46573512-5c1dff00-c94b-11e8-8a13-7d758ed3563d.png))
+ - #3230 ([archive](http://web.archive.org/web/20181005184903/https://github.com/rust-lang-nursery/rust-clippy/issues/3230), [screenshot](https://user-images.githubusercontent.com/1617736/46573513-5cb69580-c94b-11e8-86b1-14ce82741e5c.png))
+
+The usernames of commenters on these issues can be found in relicense_comments.txt
+
+There are a couple people in relicense_comments.txt who are not found in contributors.txt:
+
+ - @EpocSquadron has [made minor text contributions to the README](https://github.com/rust-lang/rust-clippy/commits?author=EpocSquadron) which have since been overwritten, and doesn't count
+ - @JayKickliter [agreed to the relicense on their pull request](https://github.com/rust-lang/rust-clippy/pull/3195#issuecomment-423781016) ([archive](https://web.archive.org/web/20181005190730/https://github.com/rust-lang/rust-clippy/pull/3195), [screenshot](https://user-images.githubusercontent.com/1617736/46573514-5cb69580-c94b-11e8-8ffb-05a5bd02e2cc.png)
+)
+ - @sanmai-NL's [contribution](https://github.com/rust-lang/rust-clippy/commits?author=sanmai-NL) is a minor one-word addition which doesn't count for copyright assignment
+ - @zmt00's [contributions](https://github.com/rust-lang/rust-clippy/commits?author=zmt00) are minor typo fixes and don't count
+ - @VKlayd has [nonminor contributions](https://github.com/rust-lang/rust-clippy/commits?author=VKlayd) which we rewrote (see below)
+ - @wartman4404 has [nonminor contributions](https://github.com/rust-lang/rust-clippy/commits?author=wartman4404) which we rewrote (see below)
+
+
+Two of these contributors had nonminor contributions (#2184, #427) requiring a rewrite, carried out in #3251 ([archive](http://web.archive.org/web/20181005192411/https://github.com/rust-lang-nursery/rust-clippy/pull/3251), [screenshot](https://user-images.githubusercontent.com/1617736/46573515-5cb69580-c94b-11e8-86e5-b456452121b2.png)
+)
+
+First, I (Manishearth) removed the lints they had added. I then documented at a high level what the lints did in #3251, asking for co-maintainers who had not seen the code for the lints to rewrite them. #2814 was rewritten by @phansch, and #427 was rewritten by @oli-obk, who did not recall having previously seen the code they were rewriting.
+
+------
+
+Since this document was written, @JayKickliter and @sanmai-ML added their consent in #3230 ([archive](http://web.archive.org/web/20181006171926/https://github.com/rust-lang-nursery/rust-clippy/issues/3230))
diff --git a/etc/relicense/contributors.txt b/etc/relicense/contributors.txt
new file mode 100644 (file)
index 0000000..e81ebf2
--- /dev/null
@@ -0,0 +1,232 @@
+0ndorio
+0xbsec
+17cupsofcoffee
+Aaron1011
+Aaronepower
+aaudiber
+afck
+alexcrichton
+AlexEne
+alexeyzab
+alexheretic
+alexreg
+alusch
+andersk
+aochagavia
+apasel422
+Arnavion
+AtheMathmo
+auscompgeek
+AVerm
+badboy
+Baelyk
+BenoitZugmeyer
+bestouff
+birkenfeld
+bjgill
+bkchr
+Bobo1239
+bood
+bootandy
+b-r-u
+budziq
+CAD97
+Caemor
+camsteffen
+carols10cents
+CBenoit
+cesarb
+cgm616
+chrisduerr
+chrisvittal
+chyvonomys
+clarcharr
+clippered
+commandline
+cramertj
+csmoe
+ctjhoa
+cuviper
+CYBAI
+darArch
+DarkEld3r
+dashed
+daubaris
+d-dorazio
+debris
+dereckson
+detrumi
+devonhollowood
+dtolnay
+durka
+dwijnand
+eddyb
+elliottneilclark
+elpiel
+ensch
+EpicatSupercell
+EpocSquadron
+erickt
+estk
+etaoins
+F001
+fanzier
+FauxFaux
+fhartwig
+flip1995
+Fraser999
+Frederick888
+frewsxcv
+gbip
+gendx
+gibfahn
+gnieto
+gnzlbg
+goodmanjonathan
+guido4000
+GuillaumeGomez
+Hanaasagi
+hdhoang
+HMPerson1
+hobofan
+iKevinY
+illicitonion
+imp
+inrustwetrust
+ishitatsuyuki
+Jascha-N
+jayhardee9
+JayKickliter
+JDemler
+jedisct1
+jmquigs
+joelgallant
+joeratt
+josephDunne
+JoshMcguigan
+joshtriplett
+jugglerchris
+karyon
+Keats
+kennytm
+Kha
+killercup
+kimsnj
+KitFreddura
+koivunej
+kraai
+kvikas
+LaurentMazare
+letheed
+llogiq
+lo48576
+lpesk
+lucab
+luisbg
+lukasstevens
+Machtan
+MaloJaffre
+Manishearth
+marcusklaas
+mark-i-m
+martiansideofthemoon
+martinlindhe
+mathstuf
+mati865
+matthiaskrgr
+mattyhall
+mbrubeck
+mcarton
+memoryleak47
+messense
+michaelrutherford
+mikerite
+mipli
+mockersf
+montrivo
+mrecachinas
+Mrmaxmeier
+mrmonday
+ms2300
+Ms2ger
+musoke
+nathan
+Nemo157
+NiekGr
+niklasf
+nrc
+nweston
+o01eg
+ogham
+oli-obk
+ordovicia
+pengowen123
+pgerber
+phansch
+philipturnbull
+pickfire
+pietro
+PixelPirate
+pizzaiter
+PSeitz
+Pyriphlegethon
+pythonesque
+quininer
+Rantanen
+rcoh
+reiner-dolp
+reujab
+Robzz
+samueltardieu
+sanmai-NL
+sanxiyn
+scott-linder
+scottmcm
+scurest
+senden9
+shahn
+shepmaster
+shnewto
+shssoichiro
+siiptuo
+sinkuu
+skade
+sourcefrog
+sourcejedi
+steveklabnik
+sunfishcode
+sunjay
+swgillespie
+Techcable
+terry90
+theemathas
+thekidxp
+theotherphil
+TimNN
+TomasKralCZ
+tomprince
+topecongiro
+tspiteri
+Twisol
+U007D
+uHOOCCOOHu
+untitaker
+upsuper
+utaal
+utam0k
+vi
+VKlayd
+Vlad-Shcherbina
+vorner
+wafflespeanut
+wartman4404
+waywardmonkeys
+yaahallo
+yangby-cryptape
+yati-sagade
+ykrivopalov
+ysimonson
+zayenz
+zmanian
+zmbush
+zmt00
diff --git a/etc/relicense/relicense_comments.txt b/etc/relicense/relicense_comments.txt
new file mode 100644 (file)
index 0000000..52c25eb
--- /dev/null
@@ -0,0 +1,227 @@
+0ndorio
+0xbsec
+17cupsofcoffee
+Aaron1011
+Aaronepower
+aaudiber
+afck
+alexcrichton
+AlexEne
+alexeyzab
+alexheretic
+alexreg
+alusch
+andersk
+aochagavia
+apasel422
+Arnavion
+AtheMathmo
+auscompgeek
+AVerm
+badboy
+Baelyk
+BenoitZugmeyer
+bestouff
+birkenfeld
+bjgill
+bkchr
+Bobo1239
+bood
+bootandy
+b-r-u
+budziq
+CAD97
+Caemor
+camsteffen
+carols10cents
+CBenoit
+cesarb
+cgm616
+chrisduerr
+chrisvittal
+chyvonomys
+clarcharr
+clippered
+commandline
+cramertj
+csmoe
+ctjhoa
+cuviper
+CYBAI
+darArch
+DarkEld3r
+dashed
+daubaris
+d-dorazio
+debris
+dereckson
+detrumi
+devonhollowood
+dtolnay
+durka
+dwijnand
+eddyb
+elliottneilclark
+elpiel
+ensch
+EpicatSupercell
+erickt
+estk
+etaoins
+F001
+fanzier
+FauxFaux
+fhartwig
+flip1995
+Fraser999
+Frederick888
+frewsxcv
+gbip
+gendx
+gibfahn
+gnieto
+gnzlbg
+goodmanjonathan
+guido4000
+GuillaumeGomez
+Hanaasagi
+hdhoang
+HMPerson1
+hobofan
+iKevinY
+illicitonion
+imp
+inrustwetrust
+ishitatsuyuki
+Jascha-N
+jayhardee9
+JDemler
+jedisct1
+jmquigs
+joelgallant
+joeratt
+josephDunne
+JoshMcguigan
+joshtriplett
+jugglerchris
+karyon
+Keats
+kennytm
+Kha
+killercup
+kimsnj
+KitFreddura
+koivunej
+kraai
+kvikas
+LaurentMazare
+letheed
+llogiq
+lo48576
+lpesk
+lucab
+luisbg
+lukasstevens
+Machtan
+MaloJaffre
+Manishearth
+marcusklaas
+mark-i-m
+martiansideofthemoon
+martinlindhe
+mathstuf
+mati865
+matthiaskrgr
+mattyhall
+mbrubeck
+mcarton
+memoryleak47
+messense
+michaelrutherford
+mikerite
+mipli
+mockersf
+montrivo
+mrecachinas
+Mrmaxmeier
+mrmonday
+ms2300
+Ms2ger
+musoke
+nathan
+Nemo157
+NiekGr
+niklasf
+nrc
+nweston
+o01eg
+ogham
+oli-obk
+ordovicia
+pengowen123
+pgerber
+phansch
+philipturnbull
+pickfire
+pietro
+PixelPirate
+pizzaiter
+PSeitz
+Pyriphlegethon
+pythonesque
+quininer
+Rantanen
+rcoh
+reiner-dolp
+reujab
+Robzz
+samueltardieu
+sanxiyn
+scott-linder
+scottmcm
+scurest
+senden9
+shahn
+shepmaster
+shnewto
+shssoichiro
+siiptuo
+sinkuu
+skade
+sourcefrog
+sourcejedi
+steveklabnik
+sunfishcode
+sunjay
+swgillespie
+Techcable
+terry90
+theemathas
+thekidxp
+theotherphil
+TimNN
+TomasKralCZ
+tommilligan
+tomprince
+topecongiro
+tspiteri
+Twisol
+U007D
+uHOOCCOOHu
+untitaker
+upsuper
+utaal
+utam0k
+vi
+Vlad-Shcherbina
+vorner
+wafflespeanut
+waywardmonkeys
+yaahallo
+yangby-cryptape
+yati-sagade
+ykrivopalov
+ysimonson
+zayenz
+zmanian
+zmbush
index ac3272030ba83ab224282aeb888d55dc2a57a471..a21e7fec6d4864cc3ec3f71682f89b1779d2cf30 100644 (file)
@@ -10,7 +10,8 @@ authors = [
 ]
 license = "MPL-2.0"
 description = "A macro to test clippy's procedural macro checks"
-repository = "https://github.com/rust-lang-nursery/rust-clippy"
+repository = "https://github.com/rust-lang/rust-clippy"
+edition = "2018"
 
 [lib]
 name = "clippy_mini_macro_test"
index 3417e603c126e574aa2a7a96ca1b775be9f1ed60..ec489344a6f1340bf4918279d14ecbde48430d8a 100644 (file)
@@ -1,4 +1,5 @@
-#![feature(use_extern_macros, proc_macro_quote, proc_macro_non_items)]
+#![feature(proc_macro_quote, proc_macro_hygiene)]
+#![deny(rust_2018_idioms)]
 extern crate proc_macro;
 
 use proc_macro::{TokenStream, quote};
@@ -7,5 +8,10 @@
 pub fn mini_macro(_: TokenStream) -> TokenStream {
     quote!(
         #[allow(unused)] fn needless_take_by_value(s: String) { println!("{}", s.len()); }
+        #[allow(unused)] fn needless_loop(items: &[u8]) {
+            for i in 0..items.len() {
+                println!("{}", items[i]);
+            }
+        }
     )
-}
\ No newline at end of file
+}
index aca17b968a8556300648d2e8648e05a9fa9ad7a7..3602f671e3dec5de2039bc0e48e3ee2a47ba15d3 100755 (executable)
@@ -4,20 +4,19 @@ set -e
 
 ./util/update_lints.py
 
-git status --short | sort | grep -v README.md | grep -v helper.txt | sort > helper.txt
-
-# abort if the files differ
-diff "publish.files" "helper.txt"
-
-rm helper.txt
-
 # add all changed files
 git add .
 git commit -m "Bump the version"
 
 set +e
 
+echo "Running \`cargo fmt\`.."
+
 cd clippy_lints && cargo fmt -- --write-mode=overwrite && cd ..
 cargo fmt -- --write-mode=overwrite
 
-echo "remember to add a git tag and running 'cargo test' before committing the rustfmt changes"
+echo "Running tests to make sure \`cargo fmt\` did not break anything.."
+
+cargo test
+
+echo "If the tests passed, review and commit the formatting changes and remember to add a git tag."
diff --git a/rust-update b/rust-update
deleted file mode 100755 (executable)
index d065319..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-if [ "$1" = '-h' ] ; then
-       echo 'Updates rustc & clippy'
-       echo 'It first checks if clippy would compile at current nightly and if so, it updates.'
-       echo 'Options:'
-       echo '-h: This help message'
-       echo '-f: Skips the check and just updates'
-       exit
-fi
-
-set -ex
-
-renice -n 10 -p $$
-
-export CARGO_INCREMENTAL=0
-export RUSTFLAGS='-C target-cpu=native'
-
-try_out() {
-       export RUSTUP_HOME=$HOME/.rustup-attempt
-       test -d $RUSTUP_HOME || (rustup toolchain add nightly && rustup default nightly)
-       rustup update
-       cargo +nightly install --force clippy
-       unset RUSTUP_HOME
-       export RUSTUP_HOME
-}
-
-[ "$1" = '-f' ] || try_out
-
-rustup update
-cargo +nightly install --force clippy
diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml
new file mode 100644 (file)
index 0000000..70ff86c
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+name = "rustc_tools_util"
+version = "0.1.1"
+authors = ["Matthias Krüger <matthias.krueger@famsik.de>"]
+description = "small helper to generate version information for git packages"
+repository = "https://github.com/rust-lang/rust-clippy"
+readme = "README.md"
+license = "MIT/Apache-2.0"
+keywords = ["rustc", "tool", "git", "version", "hash"]
+categories = ["development-tools"]
+edition = "2018"
+[dependencies]
diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md
new file mode 100644 (file)
index 0000000..79c90b8
--- /dev/null
@@ -0,0 +1,62 @@
+# rustc_tools_util
+
+A small tool to help you generate version information
+for packages installed from a git repo
+
+## Usage
+
+Add a `build.rs` file to your repo and list it in `Cargo.toml`
+````
+build = "build.rs"
+````
+
+List rustc_tools_util as regular AND build dependency.
+````
+[dependencies]
+rustc_tools_util = "0.1"
+
+[build-dependencies]
+rustc_tools_util = "0.1"
+````
+
+In `build.rs`, generate the data in your `main()`
+````rust
+fn main() {
+    println!(
+        "cargo:rustc-env=GIT_HASH={}",
+        rustc_tools_util::get_commit_hash().unwrap_or_default()
+    );
+    println!(
+        "cargo:rustc-env=COMMIT_DATE={}",
+        rustc_tools_util::get_commit_date().unwrap_or_default()
+    );
+    println!(
+        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
+        rustc_tools_util::get_channel_from_compiler_output().unwrap_or_default()
+    );
+}
+
+````
+
+Use the version information in your main.rs
+````rust
+use rustc_tools_util::*;
+
+fn show_version() {
+    let version_info = rustc_tools_util::get_version_info!();
+    println!("{}", version_info);
+}
+````
+This gives the following output in clippy:
+`clippy 0.0.212 (a416c5e 2018-12-14)`
+
+
+## License
+
+Copyright 2014-2019 The Rust Project Developers
+
+Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+<LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+option. All files in the project carrying such notice may not be
+copied, modified, or distributed except according to those terms.
diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs
new file mode 100644 (file)
index 0000000..8f89d50
--- /dev/null
@@ -0,0 +1,158 @@
+use std::env;
+
+#[macro_export]
+macro_rules! get_version_info {
+    () => {{
+        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
+        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
+        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
+        let crate_name = String::from(env!("CARGO_PKG_NAME"));
+
+        let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
+        let commit_hash = option_env!("GIT_HASH").map(str::to_string);
+        let commit_date = option_env!("COMMIT_DATE").map(str::to_string);
+
+        VersionInfo {
+            major,
+            minor,
+            patch,
+            host_compiler,
+            commit_hash,
+            commit_date,
+            crate_name,
+        }
+    }};
+}
+
+// some code taken and adapted from RLS and cargo
+pub struct VersionInfo {
+    pub major: u8,
+    pub minor: u8,
+    pub patch: u16,
+    pub host_compiler: Option<String>,
+    pub commit_hash: Option<String>,
+    pub commit_date: Option<String>,
+    pub crate_name: String,
+}
+
+impl std::fmt::Display for VersionInfo {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let hash = self.commit_hash.clone().unwrap_or_default();
+        let hash_trimmed = hash.trim();
+
+        let date = self.commit_date.clone().unwrap_or_default();
+        let date_trimmed = date.trim();
+
+        if (hash_trimmed.len() + date_trimmed.len()) > 0 {
+            write!(
+                f,
+                "{} {}.{}.{} ({} {})",
+                self.crate_name, self.major, self.minor, self.patch, hash_trimmed, date_trimmed,
+            )?;
+        } else {
+            write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
+        }
+
+        Ok(())
+    }
+}
+
+impl std::fmt::Debug for VersionInfo {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}",
+            self.crate_name, self.major, self.minor, self.patch,
+        )?;
+        if self.commit_hash.is_some() {
+            write!(
+                f,
+                ", commit_hash: \"{}\", commit_date: \"{}\" }}",
+                self.commit_hash.clone().unwrap_or_default().trim(),
+                self.commit_date.clone().unwrap_or_default().trim()
+            )?;
+        } else {
+            write!(f, " }}")?;
+        }
+
+        Ok(())
+    }
+}
+
+pub fn get_commit_hash() -> Option<String> {
+    std::process::Command::new("git")
+        .args(&["rev-parse", "--short", "HEAD"])
+        .output()
+        .ok()
+        .and_then(|r| String::from_utf8(r.stdout).ok())
+}
+
+pub fn get_commit_date() -> Option<String> {
+    std::process::Command::new("git")
+        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
+        .output()
+        .ok()
+        .and_then(|r| String::from_utf8(r.stdout).ok())
+}
+
+pub fn get_channel() -> Option<String> {
+    match env::var("CFG_RELEASE_CHANNEL") {
+        Ok(channel) => Some(channel),
+        Err(_) => {
+            // if that failed, try to ask rustc -V, do some parsing and find out
+            match std::process::Command::new("rustc")
+                .arg("-V")
+                .output()
+                .ok()
+                .and_then(|r| String::from_utf8(r.stdout).ok())
+            {
+                Some(rustc_output) => {
+                    if rustc_output.contains("beta") {
+                        Some(String::from("beta"))
+                    } else if rustc_output.contains("stable") {
+                        Some(String::from("stable"))
+                    } else {
+                        // default to nightly if we fail to parse
+                        Some(String::from("nightly"))
+                    }
+                },
+                // default to nightly
+                None => Some(String::from("nightly")),
+            }
+        },
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_struct_local() {
+        let vi = get_version_info!();
+        assert_eq!(vi.major, 0);
+        assert_eq!(vi.minor, 1);
+        assert_eq!(vi.patch, 1);
+        assert_eq!(vi.crate_name, "rustc_tools_util");
+        // hard to make positive tests for these since they will always change
+        assert!(vi.commit_hash.is_none());
+        assert!(vi.commit_date.is_none());
+    }
+
+    #[test]
+    fn test_display_local() {
+        let vi = get_version_info!();
+        assert_eq!(vi.to_string(), "rustc_tools_util 0.1.1");
+    }
+
+    #[test]
+    fn test_debug_local() {
+        let vi = get_version_info!();
+        let s = format!("{:?}", vi);
+        assert_eq!(
+            s,
+            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 1, patch: 1 }"
+        );
+    }
+
+}
index 6776a88294c54e4898a666b4b75868260a528e40..797eccdad99ec9652ad3e1ff737614c60a820d58 100644 (file)
@@ -2,3 +2,5 @@ max_width = 120
 comment_width = 100
 match_block_trailing_comma = true
 wrap_comments = true
+
+error_on_line_overflow = true
diff --git a/setup-toolchain.sh b/setup-toolchain.sh
new file mode 100755 (executable)
index 0000000..f8d764b
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+# Set up the appropriate rustc toolchain
+
+cd $(dirname $0)
+
+cargo install rustup-toolchain-install-master --debug || echo "rustup-toolchain-install-master already installed"
+RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}')
+rustup-toolchain-install-master -f -n master $RUSTC_HASH
+rustup override set master
index e9e81bb88e3de13e90e2446ababa441147e9e4b4..f4a656722b9d067ef657d23d3029f9701427b0fd 100644 (file)
-// error-pattern:yummy
-#![feature(box_syntax)]
 #![feature(rustc_private)]
-#![allow(unknown_lints, missing_docs_in_private_items)]
 
-use rustc_driver::{self, driver::CompileController, Compilation};
-use rustc_plugin;
+// FIXME: switch to something more ergonomic here, once available.
+// (Currently there is no way to opt into sysroot crates without `extern crate`.)
+#[allow(unused_extern_crates)]
+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::*;
+
+use std::path::Path;
 use std::process::{exit, Command};
 
-#[allow(print_stdout)]
-fn show_version() {
-    println!(env!("CARGO_PKG_VERSION"));
-}
+/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
+/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
+fn arg_value<'a>(
+    args: impl IntoIterator<Item = &'a String>,
+    find_arg: &str,
+    pred: impl Fn(&str) -> bool,
+) -> Option<&'a str> {
+    let mut args = args.into_iter().map(String::as_str);
 
-pub fn main() {
-    use std::env;
+    while let Some(arg) = args.next() {
+        let arg: Vec<_> = arg.splitn(2, '=').collect();
+        if arg.get(0) != Some(&find_arg) {
+            continue;
+        }
 
-    if std::env::args().any(|a| a == "--version" || a == "-V") {
-        show_version();
-        return;
+        let value = arg.get(1).cloned().or_else(|| args.next());
+        if value.as_ref().map_or(false, |p| pred(p)) {
+            return value;
+        }
     }
+    None
+}
 
-    let sys_root = option_env!("SYSROOT")
-        .map(String::from)
-        .or_else(|| std::env::var("SYSROOT").ok())
-        .or_else(|| {
-            let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
-            let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
-            home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain)))
-        })
-        .or_else(|| {
-            Command::new("rustc")
-                .arg("--print")
-                .arg("sysroot")
-                .output()
-                .ok()
-                .and_then(|out| String::from_utf8(out.stdout).ok())
-                .map(|s| s.trim().to_owned())
-        })
-        .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
+#[test]
+fn test_arg_value() {
+    let args: Vec<_> = ["--bar=bar", "--foobar", "123", "--foo"]
+        .iter()
+        .map(std::string::ToString::to_string)
+        .collect();
 
-    // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
-    // We're invoking the compiler programmatically, so we ignore this/
-    let mut orig_args: Vec<String> = env::args().collect();
-    if orig_args.len() <= 1 {
-        std::process::exit(1);
-    }
-    if orig_args[1] == "rustc" {
-        // we still want to be able to invoke it normally though
-        orig_args.remove(1);
-    }
-    // this conditional check for the --sysroot flag is there so users can call
-    // `clippy_driver` directly
-    // without having to pass --sysroot or anything
-    let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
-        orig_args.clone()
-    } else {
-        orig_args
-            .clone()
-            .into_iter()
-            .chain(Some("--sysroot".to_owned()))
-            .chain(Some(sys_root))
-            .collect()
-    };
-
-    // this check ensures that dependencies are built but not linted and the final
-    // crate is
-    // linted but not built
-    let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true")
-        || orig_args.iter().any(|s| s == "--emit=dep-info,metadata");
-
-    if clippy_enabled {
-        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
-        if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
-            args.extend(
-                extra_args
-                    .split("__CLIPPY_HACKERY__")
-                    .filter(|s| !s.is_empty())
-                    .map(str::to_owned),
-            );
+    assert_eq!(arg_value(None, "--foobar", |_| true), None);
+    assert_eq!(arg_value(&args, "--bar", |_| false), None);
+    assert_eq!(arg_value(&args, "--bar", |_| true), Some("bar"));
+    assert_eq!(arg_value(&args, "--bar", |p| p == "bar"), Some("bar"));
+    assert_eq!(arg_value(&args, "--bar", |p| p == "foo"), None);
+    assert_eq!(arg_value(&args, "--foobar", |p| p == "foo"), None);
+    assert_eq!(arg_value(&args, "--foobar", |p| p == "123"), Some("123"));
+    assert_eq!(arg_value(&args, "--foo", |_| true), None);
+}
+
+#[allow(clippy::too_many_lines)]
+
+struct ClippyCallbacks;
+
+impl rustc_driver::Callbacks for ClippyCallbacks {
+    fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool {
+        let sess = compiler.session();
+        let mut registry = rustc_plugin::registry::Registry::new(
+            sess,
+            compiler
+                .parse()
+                .expect(
+                    "at this compilation stage \
+                     the crate must be parsed",
+                )
+                .peek()
+                .span,
+        );
+        registry.args_hidden = Some(Vec::new());
+
+        let conf = clippy_lints::read_conf(&registry);
+        clippy_lints::register_plugins(&mut registry, &conf);
+
+        let rustc_plugin::registry::Registry {
+            early_lint_passes,
+            late_lint_passes,
+            lint_groups,
+            llvm_passes,
+            attributes,
+            ..
+        } = registry;
+        let mut ls = sess.lint_store.borrow_mut();
+        for pass in early_lint_passes {
+            ls.register_early_pass(Some(sess), true, false, pass);
         }
+        for pass in late_lint_passes {
+            ls.register_late_pass(Some(sess), true, false, false, pass);
+        }
+
+        for (name, (to, deprecated_name)) in lint_groups {
+            ls.register_group(Some(sess), true, name, deprecated_name, to);
+        }
+        clippy_lints::register_pre_expansion_lints(sess, &mut ls, &conf);
+        clippy_lints::register_renamed(&mut ls);
+
+        sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
+        sess.plugin_attributes.borrow_mut().extend(attributes);
+
+        // Continue execution
+        true
     }
+}
 
-    let mut controller = CompileController::basic();
-    if clippy_enabled {
-        controller.after_parse.callback = Box::new(move |state| {
-            let mut registry = rustc_plugin::registry::Registry::new(
-                state.session,
-                state
-                    .krate
-                    .as_ref()
-                    .expect(
-                        "at this compilation stage \
-                         the crate must be parsed",
-                    )
-                    .span,
-            );
-            registry.args_hidden = Some(Vec::new());
-            clippy_lints::register_plugins(&mut registry);
-
-            let rustc_plugin::registry::Registry {
-                early_lint_passes,
-                late_lint_passes,
-                lint_groups,
-                llvm_passes,
-                attributes,
-                ..
-            } = registry;
-            let sess = &state.session;
-            let mut ls = sess.lint_store.borrow_mut();
-            for pass in early_lint_passes {
-                ls.register_early_pass(Some(sess), true, pass);
-            }
-            for pass in late_lint_passes {
-                ls.register_late_pass(Some(sess), true, pass);
+pub fn main() {
+    rustc_driver::init_rustc_env_logger();
+    exit(
+        rustc_driver::report_ices_to_stderr_if_any(move || {
+            use std::env;
+
+            if std::env::args().any(|a| a == "--version" || a == "-V") {
+                let version_info = rustc_tools_util::get_version_info!();
+                println!("{}", version_info);
+                exit(0);
             }
 
-            for (name, to) in lint_groups {
-                ls.register_group(Some(sess), true, name, to);
+            let mut orig_args: Vec<String> = env::args().collect();
+
+            // Get the sysroot, looking from most specific to this invocation to the least:
+            // - command line
+            // - runtime environment
+            //    - SYSROOT
+            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
+            // - sysroot from rustc in the path
+            // - compile-time environment
+            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
+            let have_sys_root_arg = sys_root_arg.is_some();
+            let sys_root = sys_root_arg
+                .map(std::string::ToString::to_string)
+                .or_else(|| std::env::var("SYSROOT").ok())
+                .or_else(|| {
+                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
+                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
+                    home.and_then(|home| toolchain.map(|toolchain| format!("{}/toolchains/{}", home, toolchain)))
+                })
+                .or_else(|| {
+                    Command::new("rustc")
+                        .arg("--print")
+                        .arg("sysroot")
+                        .output()
+                        .ok()
+                        .and_then(|out| String::from_utf8(out.stdout).ok())
+                        .map(|s| s.trim().to_owned())
+                })
+                .or_else(|| option_env!("SYSROOT").map(String::from))
+                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
+
+            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
+            // We're invoking the compiler programmatically, so we ignore this/
+            if orig_args.len() <= 1 {
+                std::process::exit(1);
             }
-            clippy_lints::register_pre_expansion_lints(sess, &mut ls);
+            if Path::new(&orig_args[1]).file_stem() == Some("rustc".as_ref()) {
+                // we still want to be able to invoke it normally though
+                orig_args.remove(1);
+            }
+            // this conditional check for the --sysroot flag is there so users can call
+            // `clippy_driver` directly
+            // without having to pass --sysroot or anything
+            let mut args: Vec<String> = if have_sys_root_arg {
+                orig_args.clone()
+            } else {
+                orig_args
+                    .clone()
+                    .into_iter()
+                    .chain(Some("--sysroot".to_owned()))
+                    .chain(Some(sys_root))
+                    .collect()
+            };
 
-            sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
-            sess.plugin_attributes.borrow_mut().extend(attributes);
-        });
-    }
-    controller.compilation_done.stop = Compilation::Stop;
+            // this check ensures that dependencies are built but not linted and the final
+            // crate is
+            // linted but not built
+            let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true")
+                || arg_value(&orig_args, "--emit", |val| val.split(',').any(|e| e == "metadata")).is_some();
 
-    if rustc_driver::run_compiler(&args, Box::new(controller), None, None)
-        .0
-        .is_err()
-    {
-        exit(101);
-    }
+            if clippy_enabled {
+                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
+                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
+                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
+                        if s.is_empty() {
+                            None
+                        } else {
+                            Some(s.to_string())
+                        }
+                    }));
+                }
+            }
+
+            let mut clippy = ClippyCallbacks;
+            let mut default = rustc_driver::DefaultCallbacks;
+            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
+                if clippy_enabled { &mut clippy } else { &mut default };
+            let args = args;
+            rustc_driver::run_compiler(&args, callbacks, None, None)
+        })
+        .and_then(|result| result)
+        .is_err() as i32,
+    )
 }
index 1123c968006ab82f70d370a5aecd55747f0d23e7..86174a6b316fc942663ef7122eb71b74a15f7bcd 100644 (file)
@@ -1,13 +1,15 @@
 // error-pattern:cargo-clippy
 #![feature(plugin_registrar)]
-#![feature(rust_2018_preview)]
 #![feature(rustc_private)]
-#![feature(macro_vis_matcher)]
-#![allow(unknown_lints)]
-#![allow(missing_docs_in_private_items)]
 #![warn(rust_2018_idioms)]
 
-use rustc_plugin::Registry;
+// FIXME: switch to something more ergonomic here, once available.
+// (Currently there is no way to opt into sysroot crates without `extern crate`.)
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+#[allow(unused_extern_crates)]
+extern crate rustc_plugin;
+use self::rustc_plugin::Registry;
 
 #[plugin_registrar]
 pub fn plugin_registrar(reg: &mut Registry<'_>) {
@@ -25,7 +27,8 @@ pub fn plugin_registrar(reg: &mut Registry<'_>) {
         }
     });
 
-    clippy_lints::register_plugins(reg);
+    let conf = clippy_lints::read_conf(reg);
+    clippy_lints::register_plugins(reg, &conf);
 }
 
 // only exists to let the dogfood integration test works.
index 057a585e3d7dbf4b389c95dd2eca103850ac63d1..e0b2bcc7266455766a5ce29556aebf82241f474b 100644 (file)
@@ -1,7 +1,4 @@
-// error-pattern:yummy
-#![feature(box_syntax)]
-#![feature(rustc_private)]
-#![allow(unknown_lints, missing_docs_in_private_items)]
+use rustc_tools_util::*;
 
 const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
 
     -D --deny OPT       Set lint denied
     -F --forbid OPT     Set lint forbidden
 
-The feature `cargo-clippy` is automatically defined for convenience. You can use
-it to allow or deny lints from the code, eg.:
+You can use tool lints to allow or deny lints from your code, eg.:
 
-    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
+    #[allow(clippy::needless_lifetimes)]
 "#;
 
-#[allow(print_stdout)]
 fn show_help() {
     println!("{}", CARGO_CLIPPY_HELP);
 }
 
-#[allow(print_stdout)]
 fn show_version() {
-    println!(env!("CARGO_PKG_VERSION"));
+    let version_info = rustc_tools_util::get_version_info!();
+    println!("{}", version_info);
 }
 
 pub fn main() {
@@ -44,6 +39,7 @@ pub fn main() {
         show_help();
         return;
     }
+
     if std::env::args().any(|a| a == "--version" || a == "-V") {
         show_version();
         return;
@@ -60,10 +56,8 @@ fn process<I>(mut old_args: I) -> Result<(), i32>
 {
     let mut args = vec!["check".to_owned()];
 
-    let mut found_dashes = false;
     for arg in old_args.by_ref() {
-        found_dashes |= arg == "--";
-        if found_dashes {
+        if arg == "--" {
             break;
         }
         args.push(arg);
@@ -81,11 +75,7 @@ fn process<I>(mut old_args: I) -> Result<(), i32>
     let target_dir = std::env::var_os("CLIPPY_DOGFOOD")
         .map(|_| {
             std::env::var_os("CARGO_MANIFEST_DIR").map_or_else(
-                || {
-                    let mut fallback = std::ffi::OsString::new();
-                    fallback.push("clippy_dogfood");
-                    fallback
-                },
+                || std::ffi::OsString::from("clippy_dogfood"),
                 |d| {
                     std::path::PathBuf::from(d)
                         .join("target")
@@ -96,6 +86,12 @@ fn process<I>(mut old_args: I) -> Result<(), i32>
         })
         .map(|p| ("CARGO_TARGET_DIR", p));
 
+    // Run the dogfood tests directly on nightly cargo. This is required due
+    // to a bug in rustup.rs when running cargo on custom toolchains. See issue #3118.
+    if std::env::var_os("CLIPPY_DOGFOOD").is_some() && cfg!(windows) {
+        args.insert(0, "+nightly".to_string());
+    }
+
     let exit_status = std::process::Command::new("cargo")
         .args(&args)
         .env("RUSTC_WRAPPER", path)
diff --git a/tests/camel_case.rs b/tests/camel_case.rs
deleted file mode 100644 (file)
index b7efbde..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-extern crate clippy_lints;
-
-use clippy_lints::utils::{camel_case_from, camel_case_until};
-
-#[test]
-fn from_full() {
-    assert_eq!(camel_case_from("AbcDef"), 0);
-    assert_eq!(camel_case_from("Abc"), 0);
-}
-
-#[test]
-fn from_partial() {
-    assert_eq!(camel_case_from("abcDef"), 3);
-    assert_eq!(camel_case_from("aDbc"), 1);
-}
-
-#[test]
-fn from_not() {
-    assert_eq!(camel_case_from("AbcDef_"), 7);
-    assert_eq!(camel_case_from("AbcDD"), 5);
-}
-
-#[test]
-fn from_caps() {
-    assert_eq!(camel_case_from("ABCD"), 4);
-}
-
-#[test]
-fn until_full() {
-    assert_eq!(camel_case_until("AbcDef"), 6);
-    assert_eq!(camel_case_until("Abc"), 3);
-}
-
-#[test]
-fn until_not() {
-    assert_eq!(camel_case_until("abcDef"), 0);
-    assert_eq!(camel_case_until("aDbc"), 0);
-}
-
-#[test]
-fn until_partial() {
-    assert_eq!(camel_case_until("AbcDef_"), 6);
-    assert_eq!(camel_case_until("CallTypeC"), 8);
-    assert_eq!(camel_case_until("AbcDD"), 3);
-}
-
-#[test]
-fn until_caps() {
-    assert_eq!(camel_case_until("ABCD"), 0);
-}
index da5c5bd3227b849d40170f30ac54133efe46470e..663e55d8ea2ba8160843c5f5efa1d36c05b49fdf 100644 (file)
@@ -1,6 +1,6 @@
 #![feature(test)]
 
-extern crate compiletest_rs as compiletest;
+use compiletest_rs as compiletest;
 extern crate test;
 
 use std::env::{set_var, var};
@@ -46,7 +46,36 @@ fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
         config.run_lib_path = rustc_lib_path();
         config.compile_lib_path = rustc_lib_path();
     }
-    config.target_rustcflags = Some(format!("-L {0} -L {0}/deps -Dwarnings", host_libs().display()));
+
+    // When we'll want to use `extern crate ..` for a dependency that is used
+    // both by the crate and the compiler itself, we can't simply pass -L flags
+    // as we'll get a duplicate matching versions. Instead, disambiguate with
+    // `--extern dep=path`.
+    // See https://github.com/rust-lang/rust-clippy/issues/4015.
+    let needs_disambiguation = ["serde"];
+    // This assumes that deps are compiled (they are for Cargo integration tests).
+    let deps = std::fs::read_dir(host_libs().join("deps")).unwrap();
+    let disambiguated = deps
+        .filter_map(|dep| {
+            let path = dep.ok()?.path();
+            let name = path.file_name()?.to_string_lossy();
+            // NOTE: This only handles a single dep
+            // https://github.com/laumann/compiletest-rs/issues/101
+            needs_disambiguation.iter().find_map(|dep| {
+                if name.starts_with(&format!("lib{}-", dep)) {
+                    Some(format!("--extern {}={}", dep, path.display()))
+                } else {
+                    None
+                }
+            })
+        })
+        .collect::<Vec<_>>();
+
+    config.target_rustcflags = Some(format!(
+        "-L {0} -L {0}/deps -Dwarnings -Zui-testing {1}",
+        host_libs().display(),
+        disambiguated.join(" ")
+    ));
 
     config.mode = cfg_mode;
     config.build_base = if rustc_test_suite().is_some() {
@@ -65,9 +94,13 @@ fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
 }
 
 fn run_mode(mode: &str, dir: PathBuf) {
-    compiletest::run_tests(&config(mode, dir));
+    let cfg = config(mode, dir);
+    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
+    cfg.clean_rmeta();
+    compiletest::run_tests(&cfg);
 }
 
+#[allow(clippy::identity_conversion)]
 fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
     let mut result = true;
     let opts = compiletest::test_opts(config);
@@ -127,7 +160,6 @@ fn prepare_env() {
 #[test]
 fn compile_test() {
     prepare_env();
-    run_mode("run-pass", "tests/run-pass".into());
     run_mode("ui", "tests/ui".into());
     run_ui_toml();
 }
index a586d89ca4f9ffc576259c470211321b150c3f8c..4153c9ef06e4cc2731f75e40c8f15387abc57188 100644 (file)
@@ -3,16 +3,57 @@ fn dogfood() {
     if option_env!("RUSTC_TEST_SUITE").is_some() {
         return;
     }
-    let root_dir = std::env::current_dir().unwrap();
-    for d in &[".", "clippy_lints"] {
-        std::env::set_current_dir(root_dir.join(d)).unwrap();
-        let output = std::process::Command::new("cargo")
-            .arg("run")
-            .arg("--bin")
-            .arg("cargo-clippy")
-            .arg("--manifest-path")
-            .arg(root_dir.join("Cargo.toml"))
-            .env("CLIPPY_DOGFOOD", "true")
+    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+    let clippy_cmd = std::path::Path::new(&root_dir)
+        .join("target")
+        .join(env!("PROFILE"))
+        .join("cargo-clippy");
+
+    let output = std::process::Command::new(clippy_cmd)
+        .current_dir(root_dir)
+        .env("CLIPPY_DOGFOOD", "1")
+        .arg("clippy-preview")
+        .arg("--all-targets")
+        .arg("--all-features")
+        .arg("--")
+        .args(&["-D", "clippy::all"])
+        .args(&["-D", "clippy::internal"])
+        .args(&["-D", "clippy::pedantic"])
+        .output()
+        .unwrap();
+    println!("status: {}", output.status);
+    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+
+    assert!(output.status.success());
+}
+
+#[test]
+fn dogfood_tests() {
+    if option_env!("RUSTC_TEST_SUITE").is_some() {
+        return;
+    }
+    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+    let clippy_cmd = std::path::Path::new(&root_dir)
+        .join("target")
+        .join(env!("PROFILE"))
+        .join("cargo-clippy");
+
+    for d in &[
+        "clippy_workspace_tests",
+        "clippy_workspace_tests/src",
+        "clippy_workspace_tests/subcrate",
+        "clippy_workspace_tests/subcrate/src",
+        "clippy_dev",
+        "rustc_tools_util",
+    ] {
+        let output = std::process::Command::new(&clippy_cmd)
+            .current_dir(root_dir.join(d))
+            .env("CLIPPY_DOGFOOD", "1")
+            .arg("clippy")
+            .arg("--")
+            .args(&["-D", "clippy::all"])
+            .args(&["-D", "clippy::pedantic"])
             .output()
             .unwrap();
         println!("status: {}", output.status);
index 8dfb8e42d6f029f44372dfa3ecec44ff4a81cbc0..15a0ea503bf3f219c6c8e3aacf3566402aeb1f49 100644 (file)
@@ -1,13 +1,12 @@
 #![feature(rustc_private)]
 
-extern crate clippy_lints;
 extern crate syntax;
 use std::collections::Bound;
 
 #[test]
 fn test_overlapping() {
     use clippy_lints::matches::overlapping;
-    use syntax::codemap::DUMMY_SP;
+    use syntax::source_map::DUMMY_SP;
 
     let sp = |s, e| clippy_lints::matches::SpannedRange {
         span: DUMMY_SP,
diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs
new file mode 100644 (file)
index 0000000..d87bb4b
--- /dev/null
@@ -0,0 +1,56 @@
+#![allow(clippy::assertions_on_constants)]
+
+use std::fs::{self, DirEntry};
+use std::path::Path;
+
+#[test]
+fn test_missing_tests() {
+    let missing_files = explore_directory(Path::new("./tests"));
+    if !missing_files.is_empty() {
+        assert!(
+            false,
+            format!(
+                "Didn't see a test file for the following files:\n\n{}\n",
+                missing_files
+                    .iter()
+                    .map(|s| format!("\t{}", s))
+                    .collect::<Vec<_>>()
+                    .join("\n")
+            )
+        );
+    }
+}
+
+/*
+Test for missing files.
+
+Since rs files are alphabetically before stderr/stdout, we can sort by the full name
+and iter in that order. If we've seen the file stem for the first time and it's not
+a rust file, it means the rust file has to be missing.
+*/
+fn explore_directory(dir: &Path) -> Vec<String> {
+    let mut missing_files: Vec<String> = Vec::new();
+    let mut current_file = String::new();
+    let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
+    files.sort_by_key(std::fs::DirEntry::path);
+    for entry in &files {
+        let path = entry.path();
+        if path.is_dir() {
+            missing_files.extend(explore_directory(&path));
+        } else {
+            let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
+            if let Some(ext) = path.extension() {
+                match ext.to_str().unwrap() {
+                    "rs" => current_file = file_stem.clone(),
+                    "stderr" | "stdout" => {
+                        if file_stem != current_file {
+                            missing_files.push(path.to_str().unwrap().to_string());
+                        }
+                    },
+                    _ => continue,
+                };
+            }
+        }
+    }
+    missing_files
+}
index 588dc741d03c9276a56e96fd27778ab5e50a9bc7..255653b4737d3453ec371d76c8c6482deea897e4 100644 (file)
@@ -1,11 +1,10 @@
 // Tests for the various helper functions used by the needless_continue
 // lint that don't belong in utils.
 
-extern crate clippy_lints;
 use clippy_lints::needless_continue::{erode_block, erode_from_back, erode_from_front};
 
 #[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn test_erode_from_back() {
     let input = "\
 {
@@ -23,7 +22,7 @@ fn test_erode_from_back() {
 }
 
 #[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn test_erode_from_back_no_brace() {
     let input = "\
 let x = 5;
@@ -35,7 +34,7 @@ fn test_erode_from_back_no_brace() {
 }
 
 #[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn test_erode_from_front() {
     let input = "
         {
@@ -54,7 +53,7 @@ fn test_erode_from_front() {
 }
 
 #[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn test_erode_from_front_no_brace() {
     let input = "
             something();
@@ -70,7 +69,7 @@ fn test_erode_from_front_no_brace() {
 }
 
 #[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
+#[rustfmt::skip]
 fn test_erode_block() {
 
     let input = "
diff --git a/tests/run-pass/associated-constant-ice.rs b/tests/run-pass/associated-constant-ice.rs
deleted file mode 100644 (file)
index 744de9b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-pub trait Trait {
-    const CONSTANT: u8;
-}
-
-impl Trait for u8 {
-    const CONSTANT: u8 = 2;
-}
-
-fn main() {
-    println!("{}", u8::CONSTANT * 10);
-}
diff --git a/tests/run-pass/cc_seme.rs b/tests/run-pass/cc_seme.rs
deleted file mode 100644 (file)
index 1539d3c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#[allow(dead_code)]
-enum Baz {
-    One,
-    Two,
-}
-
-struct Test {
-    t: Option<usize>,
-    b: Baz,
-}
-
-fn main() { }
-
-pub fn foo() {
-    use Baz::*;
-    let x = Test { t: Some(0), b: One };
-
-    match x {
-        Test { t: Some(_), b: One } => unreachable!(),
-        Test {
-            t: Some(42),
-            b: Two,
-        } => unreachable!(),
-        Test { t: None, .. } => unreachable!(),
-        Test { .. } => unreachable!(),
-    }
-}
diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs
deleted file mode 100644 (file)
index 21ed2db..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-#![deny(clippy)]
-#![allow(unused_imports)]
-
-use std::*;
-
-fn main() { }
diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs
deleted file mode 100644 (file)
index 780df52..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-#![allow(clippy)]
-
-fn main() {
-    match 1 {
-        1 => {}
-        2 => {
-            [0; 1];
-        }
-        _ => {}
-    }
-}
diff --git a/tests/run-pass/ice-1782.rs b/tests/run-pass/ice-1782.rs
deleted file mode 100644 (file)
index fcd3e7c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#![allow(dead_code, unused_variables)]
-
-/// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
-///
-/// Issue: https://github.com/rust-lang-nursery/rust-clippy/issues/1782
-
-use std::{mem, ptr};
-
-fn spanless_eq_ice() {
-    let txt = "something";
-    match txt {
-        "something" => unsafe { ptr::write(ptr::null_mut() as *mut u32, mem::transmute::<[u8; 4], _>([0, 0, 0, 255])) },
-        _ => unsafe { ptr::write(ptr::null_mut() as *mut u32, mem::transmute::<[u8; 4], _>([13, 246, 24, 255])) },
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs
deleted file mode 100644 (file)
index 2963398..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-#![allow(clippy)]
-
-fn main() { }
-
-pub trait Convert {
-    type Action: From<*const f64>;
-
-    fn convert(val: *const f64) -> Self::Action {
-        val.into()
-    }
-}
diff --git a/tests/run-pass/ice-2499.rs b/tests/run-pass/ice-2499.rs
deleted file mode 100644 (file)
index 01deb7a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![allow(dead_code, char_lit_as_u8, needless_bool)]
-
-/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
-///
-/// Issue: https://github.com/rust-lang-nursery/rust-clippy/issues/2499
-
-fn f(s: &[u8]) -> bool {
-    let t = s[0] as char;
-
-    match t {
-        'E' | 'W' => {}
-        'T' => if s[0..4] != ['0' as u8; 4] {
-            return false;
-        } else {
-            return true;
-        },
-        _ => {
-            return false;
-        }
-    }
-    true
-}
-
-fn main() {}
diff --git a/tests/run-pass/ice-2594.rs b/tests/run-pass/ice-2594.rs
deleted file mode 100644 (file)
index 7cd30b6..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#![allow(dead_code, unused_variables)]
-
-/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
-///
-/// Issue: https://github.com/rust-lang-nursery/rust-clippy/issues/2594
-
-fn spanless_hash_ice() {
-    let txt = "something";
-    let empty_header: [u8; 1] = [1; 1];
-
-    match txt {
-        "something" => {
-            let mut headers = [empty_header; 1];
-        }
-        "" => (),
-        _ => (),
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/ice-2727.rs b/tests/run-pass/ice-2727.rs
deleted file mode 100644 (file)
index 79c6f1c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-pub fn f(new: fn()) {
-    new();
-}
-
-fn main() {}
diff --git a/tests/run-pass/ice-2760.rs b/tests/run-pass/ice-2760.rs
deleted file mode 100644 (file)
index 01ca6d4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#![allow(unused_variables, blacklisted_name, needless_pass_by_value, dead_code)]
-
-// This should not compile-fail with:
-//
-//      error[E0277]: the trait bound `T: Foo` is not satisfied
-//
-// See https://github.com/rust-lang-nursery/rust-clippy/issues/2760
-
-trait Foo {
-    type Bar;
-}
-
-struct Baz<T: Foo> {
-    bar: T::Bar,
-}
-
-fn take<T: Foo>(baz: Baz<T>) {}
-
-fn main() {}
diff --git a/tests/run-pass/ice-2774.rs b/tests/run-pass/ice-2774.rs
deleted file mode 100644 (file)
index c6d9bb4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-use std::collections::HashSet;
-
-// See https://github.com/rust-lang-nursery/rust-clippy/issues/2774
-
-#[derive(Eq, PartialEq, Debug, Hash)]
-pub struct Bar {
-    foo: Foo,
-}
-
-#[derive(Eq, PartialEq, Debug, Hash)]
-pub struct Foo {}
-
-#[allow(implicit_hasher)]
-// This should not cause a 'cannot relate bound region' ICE
-pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
-    let mut foos = HashSet::new();
-    foos.extend(
-        bars.iter().map(|b| &b.foo)
-    );
-}
-
-#[allow(implicit_hasher)]
-// Also this should not cause a 'cannot relate bound region' ICE
-pub fn add_barfoos_to_foos2(bars: &HashSet<&Bar>) {
-    let mut foos = HashSet::new();
-    foos.extend(
-        bars.iter().map(|b| &b.foo)
-    );
-}
-
-fn main() {}
diff --git a/tests/run-pass/ice-2865.rs b/tests/run-pass/ice-2865.rs
deleted file mode 100644 (file)
index 430de25..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#[allow(dead_code)]
-struct Ice {
-    size: String
-}
-
-impl<'a> From<String> for Ice {
-    fn from(_: String) -> Self {
-        let text = || "iceberg".to_string();
-        Self { size: text() }
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs
deleted file mode 100644 (file)
index a1e3a67..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-#![deny(clippy)]
-
-fn core() {}
-
-fn main() {
-    core();
-}
diff --git a/tests/run-pass/ice_exacte_size.rs b/tests/run-pass/ice_exacte_size.rs
deleted file mode 100644 (file)
index 914153c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#![deny(clippy)]
-
-#[allow(dead_code)]
-struct Foo;
-
-impl Iterator for Foo {
-    type Item = ();
-
-    fn next(&mut self) -> Option<()> {
-        let _ = self.len() == 0;
-        unimplemented!()
-    }
-}
-
-impl ExactSizeIterator for Foo {}
-
-fn main() {}
diff --git a/tests/run-pass/if_same_then_else.rs b/tests/run-pass/if_same_then_else.rs
deleted file mode 100644 (file)
index eb14ce8..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#![deny(if_same_then_else)]
-
-fn main() {}
-
-pub fn foo(a: i32, b: i32) -> Option<&'static str> {
-    if a == b {
-        None
-    } else if a > b {
-        Some("a pfeil b")
-    } else {
-        None
-    }
-}
diff --git a/tests/run-pass/issue-2862.rs b/tests/run-pass/issue-2862.rs
deleted file mode 100644 (file)
index b35df66..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-pub trait FooMap {
-    fn map<B, F: Fn() -> B>(&self, f: F) -> B;
-}
-
-impl FooMap for bool {
-    fn map<B, F: Fn() -> B>(&self, f: F) -> B {
-        f()
-    }
-}
-
-fn main() {
-    let a = true;
-    a.map(|| false);
-}
diff --git a/tests/run-pass/issue-825.rs b/tests/run-pass/issue-825.rs
deleted file mode 100644 (file)
index 79df259..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#![allow(warnings)]
-
-// this should compile in a reasonable amount of time
-fn rust_type_id(name: &str) {
-    if "bool" == &name[..] || "uint" == &name[..] || "u8" == &name[..] || "u16" == &name[..] || "u32" == &name[..]
-        || "f32" == &name[..] || "f64" == &name[..] || "i8" == &name[..] || "i16" == &name[..]
-        || "i32" == &name[..] || "i64" == &name[..] || "Self" == &name[..] || "str" == &name[..]
-    {
-        unreachable!();
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/issues_loop_mut_cond.rs b/tests/run-pass/issues_loop_mut_cond.rs
deleted file mode 100644 (file)
index 6ecd40b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#![allow(dead_code)]
-
-/// Issue: https://github.com/rust-lang-nursery/rust-clippy/issues/2596
-pub fn loop_on_block_condition(u: &mut isize) {
-    while { *u < 0 } {
-        *u += 1;
-    }
-}
-
-/// https://github.com/rust-lang-nursery/rust-clippy/issues/2584
-fn loop_with_unsafe_condition(ptr: *const u8) {
-    let mut len = 0;
-    while unsafe { *ptr.offset(len) } != 0 {
-        len += 1;
-    }
-}
-
-/// https://github.com/rust-lang-nursery/rust-clippy/issues/2710
-static mut RUNNING: bool = true;
-fn loop_on_static_condition() {
-    unsafe {
-        while RUNNING {
-            RUNNING = false;
-        }
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/match_same_arms_const.rs b/tests/run-pass/match_same_arms_const.rs
deleted file mode 100644 (file)
index 08acc2b..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#![deny(match_same_arms)]
-
-const PRICE_OF_SWEETS: u32 = 5;
-const PRICE_OF_KINDNESS: u32 = 0;
-const PRICE_OF_DRINKS: u32 = 5;
-
-pub fn price(thing: &str) -> u32 {
-    match thing {
-        "rolo" => PRICE_OF_SWEETS,
-        "advice" => PRICE_OF_KINDNESS,
-        "juice" => PRICE_OF_DRINKS,
-        _ => panic!()
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs
deleted file mode 100644 (file)
index 2b916c0..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#![deny(mut_mut, zero_ptr, cmp_nan)]
-#![allow(dead_code)]
-
-// compiletest + extern crates doesn't work together
-//#[macro_use]
-//extern crate lazy_static;
-
-//use std::collections::HashMap;
-
-// ensure that we don't suggest `is_nan` and `is_null` inside constants
-// FIXME: once const fn is stable, suggest these functions again in constants
-const BAA: *const i32 = 0 as *const i32;
-static mut BAR: *const i32 = BAA;
-static mut FOO: *const i32 = 0 as *const i32;
-static mut BUH: bool = 42.0 < std::f32::NAN;
-
-#[allow(unused_variables, unused_mut)]
-fn main() {
-    /*
-    lazy_static! {
-        static ref MUT_MAP : HashMap<usize, &'static str> = {
-            let mut m = HashMap::new();
-            m.insert(0, "zero");
-            m
-        };
-        static ref MUT_COUNT : usize = MUT_MAP.len();
-    }
-    assert_eq!(*MUT_COUNT, 1);
-    */
-    // FIXME: don't lint in array length, requires `check_body`
-    //let _ = [""; (42.0 < std::f32::NAN) as usize];
-}
diff --git a/tests/run-pass/needless_borrow_fp.rs b/tests/run-pass/needless_borrow_fp.rs
deleted file mode 100644 (file)
index 9dc5080..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#[deny(clippy)]
-
-#[derive(Debug)]
-pub enum Error {
-    Type(
-        &'static str,
-    ),
-}
-
-fn main() {}
diff --git a/tests/run-pass/needless_lifetimes_impl_trait.rs b/tests/run-pass/needless_lifetimes_impl_trait.rs
deleted file mode 100644 (file)
index 700215b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-
-#![deny(needless_lifetimes)]
-#![allow(dead_code)]
-
-trait Foo {}
-
-struct Bar {}
-
-struct Baz<'a> {
-    bar: &'a Bar,
-}
-
-impl<'a> Foo for Baz<'a> {}
-
-impl Bar {
-    fn baz<'a>(&'a self) -> impl Foo + 'a {
-        Baz { bar: self }
-    }
-}
-
-fn main() {}
diff --git a/tests/run-pass/procedural_macro.rs b/tests/run-pass/procedural_macro.rs
deleted file mode 100644 (file)
index 2b7ff12..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#[macro_use]
-extern crate clippy_mini_macro_test;
-
-#[deny(warnings)]
-fn main() {
-    let x = Foo;
-    println!("{:?}", x);
-}
-
-
-#[derive(ClippyMiniMacroTest, Debug)]
-struct Foo;
\ No newline at end of file
diff --git a/tests/run-pass/regressions.rs b/tests/run-pass/regressions.rs
deleted file mode 100644 (file)
index d5e343c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-#![allow(blacklisted_name)]
-
-pub fn foo(bar: *const u8) {
-    println!("{:#p}", bar);
-}
-
-fn main() {}
diff --git a/tests/run-pass/returns.rs b/tests/run-pass/returns.rs
deleted file mode 100644 (file)
index 882d3aa..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#[deny(warnings)]
-fn cfg_return() -> i32 {
-    #[cfg(unix)] return 1;
-    #[cfg(not(unix))] return 2;
-}
-
-#[deny(warnings)]
-fn cfg_let_and_return() -> i32 {
-    #[cfg(unix)]
-    let x = 1;
-    #[cfg(not(unix))]
-    let x = 2;
-    x
-}
-
-fn main() {
-    cfg_return();
-    cfg_let_and_return();
-}
diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs
deleted file mode 100644 (file)
index b8fa729..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-#![warn(single_match_else)]
-
-fn main() {
-    let n = match (42, 43) {
-        (42, n) => n,
-        _ => panic!("typeck error"),
-    };
-    assert_eq!(n, 43);
-}
diff --git a/tests/run-pass/used_underscore_binding_macro.rs b/tests/run-pass/used_underscore_binding_macro.rs
deleted file mode 100644 (file)
index c9c7725..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-#[macro_use]
-extern crate serde_derive;
-
-/// Test that we do not lint for unused underscores in a `MacroAttribute`
-/// expansion
-#[deny(used_underscore_binding)]
-#[derive(Deserialize)]
-struct MacroAttributesTest {
-    _foo: u32,
-}
-
-#[test]
-fn macro_attributes_test() {
-    let _ = MacroAttributesTest { _foo: 0 };
-}
-
-fn main() {}
diff --git a/tests/run-pass/whitelist/clippy.toml b/tests/run-pass/whitelist/clippy.toml
deleted file mode 100644 (file)
index 9f87de2..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# this is ignored by Clippy, but allowed for other tools like clippy-service
-[third-party]
-clippy-feature = "nightly"
diff --git a/tests/run-pass/whitelist/conf_whitelisted.rs b/tests/run-pass/whitelist/conf_whitelisted.rs
deleted file mode 100644 (file)
index f328e4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-fn main() {}
diff --git a/tests/trim_multiline.rs b/tests/trim_multiline.rs
deleted file mode 100644 (file)
index d6de36b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/// test the multiline-trim function
-extern crate clippy_lints;
-
-use clippy_lints::utils::trim_multiline;
-
-#[test]
-fn test_single_line() {
-    assert_eq!("", trim_multiline("".into(), false));
-    assert_eq!("...", trim_multiline("...".into(), false));
-    assert_eq!("...", trim_multiline("    ...".into(), false));
-    assert_eq!("...", trim_multiline("\t...".into(), false));
-    assert_eq!("...", trim_multiline("\t\t...".into(), false));
-}
-
-#[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
-fn test_block() {
-    assert_eq!("\
-if x {
-    y
-} else {
-    z
-}", trim_multiline("    if x {
-        y
-    } else {
-        z
-    }".into(), false));
-    assert_eq!("\
-if x {
-\ty
-} else {
-\tz
-}", trim_multiline("    if x {
-    \ty
-    } else {
-    \tz
-    }".into(), false));
-}
-
-#[test]
-#[cfg_attr(rustfmt, rustfmt_skip)]
-fn test_empty_line() {
-    assert_eq!("\
-if x {
-    y
-
-} else {
-    z
-}", trim_multiline("    if x {
-        y
-
-    } else {
-        z
-    }".into(), false));
-}
index 325688ac7daa9a041077bb7172c4a2f949d5da12..3b9458fc2840e7494cab39c77c379854f0ddc777 100644 (file)
@@ -1,6 +1,3 @@
 // error-pattern: error reading Clippy's configuration file
 
-
-
-
 fn main() {}
index f97f5802b1330cd94fcdf8eea5d761ddbf1caa45..8a0062423ad168f2cf09730cbb234d2c689a9f47 100644 (file)
@@ -1,6 +1,4 @@
-// error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer`
-
-
-
+// error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a
+// `Vec < String >` but is a `integer`
 
 fn main() {}
diff --git a/tests/ui-toml/conf_deprecated_key/clippy.toml b/tests/ui-toml/conf_deprecated_key/clippy.toml
new file mode 100644 (file)
index 0000000..ac47b19
--- /dev/null
@@ -0,0 +1,6 @@
+# that one is an error
+cyclomatic-complexity-threshold = 42
+
+# that one is white-listed
+[third-party]
+clippy-feature = "nightly"
diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
new file mode 100644 (file)
index 0000000..2577c1e
--- /dev/null
@@ -0,0 +1,4 @@
+// error-pattern: error reading Clippy's configuration file: found deprecated field
+// `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead.
+
+fn main() {}
diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
new file mode 100644 (file)
index 0000000..34267c0
--- /dev/null
@@ -0,0 +1,4 @@
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: found deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead.
+
+error: aborting due to previous error
+
diff --git a/tests/ui-toml/functions_maxlines/clippy.toml b/tests/ui-toml/functions_maxlines/clippy.toml
new file mode 100644 (file)
index 0000000..951dbb5
--- /dev/null
@@ -0,0 +1 @@
+too-many-lines-threshold = 1
diff --git a/tests/ui-toml/functions_maxlines/test.rs b/tests/ui-toml/functions_maxlines/test.rs
new file mode 100644 (file)
index 0000000..a47677a
--- /dev/null
@@ -0,0 +1,45 @@
+#![warn(clippy::too_many_lines)]
+
+// This function should be considered one line.
+fn many_comments_but_one_line_of_code() {
+    /* println!("This is good."); */
+    // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* println!("This is good.");
+    println!("This is good.");
+    println!("This is good."); */
+    println!("This is good.");
+}
+
+// This should be considered two and a fail.
+fn too_many_lines() {
+    println!("This is bad.");
+    println!("This is bad.");
+}
+
+// This should be considered one line.
+#[rustfmt::skip]
+fn comment_starts_after_code() {
+    let _ = 5; /* closing comment. */ /*
+    this line shouldn't be counted theoretically.
+    */
+}
+
+// This should be considered one line.
+fn comment_after_code() {
+    let _ = 5; /* this line should get counted once. */
+}
+
+// This should fail since it is technically two lines.
+#[rustfmt::skip]
+fn comment_before_code() {
+    let _ = "test";
+    /* This comment extends to the front of
+    the code but this line should still count. */ let _ = 5;
+}
+
+// This should be considered one line.
+fn main() {}
diff --git a/tests/ui-toml/functions_maxlines/test.stderr b/tests/ui-toml/functions_maxlines/test.stderr
new file mode 100644 (file)
index 0000000..4b77ac5
--- /dev/null
@@ -0,0 +1,23 @@
+error: This function has a large number of lines.
+  --> $DIR/test.rs:18:1
+   |
+LL | / fn too_many_lines() {
+LL | |     println!("This is bad.");
+LL | |     println!("This is bad.");
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::too-many-lines` implied by `-D warnings`
+
+error: This function has a large number of lines.
+  --> $DIR/test.rs:38:1
+   |
+LL | / fn comment_before_code() {
+LL | |     let _ = "test";
+LL | |     /* This comment extends to the front of
+LL | |     the code but this line should still count. */ let _ = 5;
+LL | | }
+   | |_^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui-toml/good_toml_no_false_negatives/clippy.toml b/tests/ui-toml/good_toml_no_false_negatives/clippy.toml
new file mode 100644 (file)
index 0000000..a1dd6b2
--- /dev/null
@@ -0,0 +1,3 @@
+# that one is white-listed
+[third-party]
+clippy-feature = "nightly"
diff --git a/tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs b/tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs
new file mode 100644 (file)
index 0000000..270b9c5
--- /dev/null
@@ -0,0 +1,3 @@
+// error-pattern: should give absolutely no error
+
+fn main() {}
index 1f1a8ee91a1827b7f8a8fdaeaa10a27446e51e03..cb35d0e8589d2e4f2052da05477757d0d609b5d3 100644 (file)
@@ -1,10 +1,7 @@
-
-
-
 #![allow(dead_code)]
-#![allow(single_match)]
+#![allow(clippy::single_match)]
 #![allow(unused_variables)]
-#![warn(blacklisted_name)]
+#![warn(clippy::blacklisted_name)]
 
 fn test(toto: ()) {}
 
index b2b0f26b1405a2205977bfd1fdc190e058e103d4..84ba77851f77e91bae30f9241053a44bf08e3170 100644 (file)
@@ -1,45 +1,45 @@
 error: use of a blacklisted/placeholder name `toto`
--> $DIR/conf_french_blacklisted_name.rs:9:9
-  |
-9 | fn test(toto: ()) {}
-  |         ^^^^
-  |
-  = note: `-D blacklisted-name` implied by `-D warnings`
 --> $DIR/conf_french_blacklisted_name.rs:6:9
+   |
+LL | fn test(toto: ()) {}
+   |         ^^^^
+   |
+   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
 
 error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:12:9
+  --> $DIR/conf_french_blacklisted_name.rs:9:9
    |
-12 |     let toto = 42;
+LL |     let toto = 42;
    |         ^^^^
 
 error: use of a blacklisted/placeholder name `tata`
-  --> $DIR/conf_french_blacklisted_name.rs:13:9
+  --> $DIR/conf_french_blacklisted_name.rs:10:9
    |
-13 |     let tata = 42;
+LL |     let tata = 42;
    |         ^^^^
 
 error: use of a blacklisted/placeholder name `titi`
-  --> $DIR/conf_french_blacklisted_name.rs:14:9
+  --> $DIR/conf_french_blacklisted_name.rs:11:9
    |
-14 |     let titi = 42;
+LL |     let titi = 42;
    |         ^^^^
 
 error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:20:10
+  --> $DIR/conf_french_blacklisted_name.rs:17:10
    |
-20 |         (toto, Some(tata), titi @ Some(_)) => (),
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
    |          ^^^^
 
 error: use of a blacklisted/placeholder name `tata`
-  --> $DIR/conf_french_blacklisted_name.rs:20:21
+  --> $DIR/conf_french_blacklisted_name.rs:17:21
    |
-20 |         (toto, Some(tata), titi @ Some(_)) => (),
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
    |                     ^^^^
 
 error: use of a blacklisted/placeholder name `titi`
-  --> $DIR/conf_french_blacklisted_name.rs:20:28
+  --> $DIR/conf_french_blacklisted_name.rs:17:28
    |
-20 |         (toto, Some(tata), titi @ Some(_)) => (),
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
    |                            ^^^^
 
 error: aborting due to 7 previous errors
index bee092a5765a9844637aa92c194aeeff1f4afcbc..f24fe51d30f070da38c0e31e49d7a1db2aef3d0f 100644 (file)
@@ -1,4 +1,4 @@
-#![allow(many_single_char_names)]
+#![allow(clippy::many_single_char_names)]
 
 #[derive(Copy, Clone)]
 struct Foo(u8);
@@ -6,11 +6,9 @@
 #[derive(Copy, Clone)]
 struct Bar(u32);
 
-fn good(a: &mut u32, b: u32, c: &Bar, d: &u32) {
-}
+fn good(a: &mut u32, b: u32, c: &Bar, d: &u32) {}
 
-fn bad(x: &u16, y: &Foo) {
-}
+fn bad(x: &u16, y: &Foo) {}
 
 fn main() {
     let (mut a, b, c, d, x, y) = (0, 0, Bar(0), 0, 0, Foo(0));
index 2d36c47c5da1bf5ded3456f86c276e604ba0b1e5..746b9ffa4af19074b10dbc86924a9909ffba6b93 100644 (file)
@@ -1,15 +1,15 @@
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/test.rs:12:11
+  --> $DIR/test.rs:11:11
    |
-12 | fn bad(x: &u16, y: &Foo) {
+LL | fn bad(x: &u16, y: &Foo) {}
    |           ^^^^ help: consider passing by value instead: `u16`
    |
-   = note: `-D trivially-copy-pass-by-ref` implied by `-D warnings`
+   = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/test.rs:12:20
+  --> $DIR/test.rs:11:20
    |
-12 | fn bad(x: &u16, y: &Foo) {
+LL | fn bad(x: &u16, y: &Foo) {}
    |                    ^^^^ help: consider passing by value instead: `Foo`
 
 error: aborting due to 2 previous errors
index bfa804558bbd07e911cf25d2b3446dee9c879552..a47569f62a3229590feb453f4a543ed7ab98317d 100644 (file)
@@ -1,6 +1,3 @@
 // error-pattern: error reading Clippy's configuration file: unknown key `foobar`
 
-
-
-
 fn main() {}
index 05a04fb377ad70c7ee8bf61d366707bfb19e1be0..cdb1576b6776969d6780183e81814c71bbe9b51d 100644 (file)
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `third-party`
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `third-party`
 
 error: aborting due to previous error
 
index acc38f15fbdc51779a20832bd599c376614c2f79..71404b68c4592de53fece1a1cbb6e07e12730e99 100755 (executable)
@@ -1,15 +1,5 @@
 #!/bin/bash
 #
-# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
 # A script to update the references for all tests. The idea is that
 # you do a run, which will generate files in the build directory
 # containing the (normalized) actual output of the compiler. You then
index aa99d35f7aa779924dd17c96675ee50449f3343f..2c4fef43d96a5502331fc498436024bb5ca6f1bd 100755 (executable)
@@ -1,14 +1,4 @@
 #!/bin/bash
-#
-# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
 
 # A script to update the references for particular tests. The idea is
 # that you do a run, which will generate files in the build directory
index 8c036e6c072557c3a4c257a39dc7098a19cf01c9..ae0727fe2ba3bf9b6c3ae62ba1cdc17664254d97 100644 (file)
@@ -1,9 +1,13 @@
-
-
-
-#![warn(absurd_extreme_comparisons)]
-#![allow(unused, eq_op, no_effect, unnecessary_operation, needless_pass_by_value)]
-
+#![warn(clippy::absurd_extreme_comparisons)]
+#![allow(
+    unused,
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::needless_pass_by_value
+)]
+
+#[rustfmt::skip]
 fn main() {
     const Z: u32 = 0;
     let u: u32 = 42;
@@ -27,7 +31,7 @@ fn main() {
     b >= true;
     false > b;
     u > 0; // ok
-    // this is handled by unit_cmp
+    // this is handled by clippy::unit_cmp
     () < {};
 }
 
index 72b2f7a3942d35c010fb85522b15c43feaf29e15..b18a943c557c70f8502a852ce1e1c47b97d3b328 100644 (file)
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:10:5
+  --> $DIR/absurd-extreme-comparisons.rs:14:5
    |
-10 |     u <= 0;
+LL |     u <= 0;
    |     ^^^^^^
    |
-   = note: `-D absurd-extreme-comparisons` implied by `-D warnings`
+   = note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings`
    = help: because 0 is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == 0 instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:11:5
+  --> $DIR/absurd-extreme-comparisons.rs:15:5
    |
-11 |     u <= Z;
+LL |     u <= Z;
    |     ^^^^^^
    |
    = help: because Z is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == Z instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:12:5
+  --> $DIR/absurd-extreme-comparisons.rs:16:5
    |
-12 |     u < Z;
+LL |     u < Z;
    |     ^^^^^
    |
    = help: because Z is the minimum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:13:5
+  --> $DIR/absurd-extreme-comparisons.rs:17:5
    |
-13 |     Z >= u;
+LL |     Z >= u;
    |     ^^^^^^
    |
    = help: because Z is the minimum value for this type, the case where the two sides are not equal never occurs, consider using Z == u instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:14:5
+  --> $DIR/absurd-extreme-comparisons.rs:18:5
    |
-14 |     Z > u;
+LL |     Z > u;
    |     ^^^^^
    |
    = help: because Z is the minimum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:15:5
+  --> $DIR/absurd-extreme-comparisons.rs:19:5
    |
-15 |     u > std::u32::MAX;
+LL |     u > std::u32::MAX;
    |     ^^^^^^^^^^^^^^^^^
    |
    = help: because std::u32::MAX is the maximum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:16:5
+  --> $DIR/absurd-extreme-comparisons.rs:20:5
    |
-16 |     u >= std::u32::MAX;
+LL |     u >= std::u32::MAX;
    |     ^^^^^^^^^^^^^^^^^^
    |
    = help: because std::u32::MAX is the maximum value for this type, the case where the two sides are not equal never occurs, consider using u == std::u32::MAX instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:17:5
+  --> $DIR/absurd-extreme-comparisons.rs:21:5
    |
-17 |     std::u32::MAX < u;
+LL |     std::u32::MAX < u;
    |     ^^^^^^^^^^^^^^^^^
    |
    = help: because std::u32::MAX is the maximum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:18:5
+  --> $DIR/absurd-extreme-comparisons.rs:22:5
    |
-18 |     std::u32::MAX <= u;
+LL |     std::u32::MAX <= u;
    |     ^^^^^^^^^^^^^^^^^^
    |
    = help: because std::u32::MAX is the maximum value for this type, the case where the two sides are not equal never occurs, consider using std::u32::MAX == u instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:19:5
+  --> $DIR/absurd-extreme-comparisons.rs:23:5
    |
-19 |     1-1 > u;
+LL |     1-1 > u;
    |     ^^^^^^^
    |
    = help: because 1-1 is the minimum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:20:5
+  --> $DIR/absurd-extreme-comparisons.rs:24:5
    |
-20 |     u >= !0;
+LL |     u >= !0;
    |     ^^^^^^^
    |
    = help: because !0 is the maximum value for this type, the case where the two sides are not equal never occurs, consider using u == !0 instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:21:5
+  --> $DIR/absurd-extreme-comparisons.rs:25:5
    |
-21 |     u <= 12 - 2*6;
+LL |     u <= 12 - 2*6;
    |     ^^^^^^^^^^^^^
    |
    = help: because 12 - 2*6 is the minimum value for this type, the case where the two sides are not equal never occurs, consider using u == 12 - 2*6 instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:23:5
+  --> $DIR/absurd-extreme-comparisons.rs:27:5
    |
-23 |     i < -127 - 1;
+LL |     i < -127 - 1;
    |     ^^^^^^^^^^^^
    |
    = help: because -127 - 1 is the minimum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:24:5
+  --> $DIR/absurd-extreme-comparisons.rs:28:5
    |
-24 |     std::i8::MAX >= i;
+LL |     std::i8::MAX >= i;
    |     ^^^^^^^^^^^^^^^^^
    |
    = help: because std::i8::MAX is the maximum value for this type, this comparison is always true
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:25:5
+  --> $DIR/absurd-extreme-comparisons.rs:29:5
    |
-25 |     3-7 < std::i32::MIN;
+LL |     3-7 < std::i32::MIN;
    |     ^^^^^^^^^^^^^^^^^^^
    |
    = help: because std::i32::MIN is the minimum value for this type, this comparison is always false
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:27:5
+  --> $DIR/absurd-extreme-comparisons.rs:31:5
    |
-27 |     b >= true;
+LL |     b >= true;
    |     ^^^^^^^^^
    |
    = help: because true is the maximum value for this type, the case where the two sides are not equal never occurs, consider using b == true instead
 
 error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
-  --> $DIR/absurd-extreme-comparisons.rs:28:5
+  --> $DIR/absurd-extreme-comparisons.rs:32:5
    |
-28 |     false > b;
+LL |     false > b;
    |     ^^^^^^^^^
    |
    = help: because false is the minimum value for this type, this comparison is always false
 
 error: <-comparison of unit values detected. This will always be false
-  --> $DIR/absurd-extreme-comparisons.rs:31:5
+  --> $DIR/absurd-extreme-comparisons.rs:35:5
    |
-31 |     () < {};
+LL |     () < {};
    |     ^^^^^^^
    |
-   = note: #[deny(unit_cmp)] on by default
+   = note: #[deny(clippy::unit_cmp)] on by default
 
 error: aborting due to 18 previous errors
 
index d353d9075d4e0488a23cdd22d3be1ad26819529b..8c295d1438a79970e4b68ef16352a03f0639c471 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#[warn(approx_constant)]
-#[allow(unused, shadow_unrelated, similar_names, unreadable_literal)]
+#[warn(clippy::approx_constant)]
+#[allow(unused, clippy::shadow_unrelated, clippy::similar_names, clippy::unreadable_literal)]
 fn main() {
     let my_e = 2.7182;
     let almost_e = 2.718;
index e5d2ba29605d6e6e4e9003be3868bd40c0d926f3..71c1c360e74a6f870efffbcf1a6dae2973a5409f 100644 (file)
 error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly
--> $DIR/approx_const.rs:7:16
-  |
-7 |     let my_e = 2.7182;
-  |                ^^^^^^
-  |
-  = note: `-D approx-constant` implied by `-D warnings`
 --> $DIR/approx_const.rs:4:16
+   |
+LL |     let my_e = 2.7182;
+   |                ^^^^^^
+   |
+   = note: `-D clippy::approx-constant` implied by `-D warnings`
 
 error: approximate value of `f{32, 64}::consts::E` found. Consider using it directly
--> $DIR/approx_const.rs:8:20
-  |
-8 |     let almost_e = 2.718;
-  |                    ^^^^^
 --> $DIR/approx_const.rs:5:20
+   |
+LL |     let almost_e = 2.718;
+   |                    ^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found. Consider using it directly
-  --> $DIR/approx_const.rs:11:24
+  --> $DIR/approx_const.rs:8:24
    |
-11 |     let my_1_frac_pi = 0.3183;
+LL |     let my_1_frac_pi = 0.3183;
    |                        ^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly
-  --> $DIR/approx_const.rs:14:28
+  --> $DIR/approx_const.rs:11:28
    |
-14 |     let my_frac_1_sqrt_2 = 0.70710678;
+LL |     let my_frac_1_sqrt_2 = 0.70710678;
    |                            ^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found. Consider using it directly
-  --> $DIR/approx_const.rs:15:32
+  --> $DIR/approx_const.rs:12:32
    |
-15 |     let almost_frac_1_sqrt_2 = 0.70711;
+LL |     let almost_frac_1_sqrt_2 = 0.70711;
    |                                ^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found. Consider using it directly
-  --> $DIR/approx_const.rs:18:24
+  --> $DIR/approx_const.rs:15:24
    |
-18 |     let my_frac_2_pi = 0.63661977;
+LL |     let my_frac_2_pi = 0.63661977;
    |                        ^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found. Consider using it directly
-  --> $DIR/approx_const.rs:21:27
+  --> $DIR/approx_const.rs:18:27
    |
-21 |     let my_frac_2_sq_pi = 1.128379;
+LL |     let my_frac_2_sq_pi = 1.128379;
    |                           ^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found. Consider using it directly
-  --> $DIR/approx_const.rs:24:24
+  --> $DIR/approx_const.rs:21:24
    |
-24 |     let my_frac_pi_2 = 1.57079632679;
+LL |     let my_frac_pi_2 = 1.57079632679;
    |                        ^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found. Consider using it directly
-  --> $DIR/approx_const.rs:27:24
+  --> $DIR/approx_const.rs:24:24
    |
-27 |     let my_frac_pi_3 = 1.04719755119;
+LL |     let my_frac_pi_3 = 1.04719755119;
    |                        ^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found. Consider using it directly
-  --> $DIR/approx_const.rs:30:24
+  --> $DIR/approx_const.rs:27:24
    |
-30 |     let my_frac_pi_4 = 0.785398163397;
+LL |     let my_frac_pi_4 = 0.785398163397;
    |                        ^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found. Consider using it directly
-  --> $DIR/approx_const.rs:33:24
+  --> $DIR/approx_const.rs:30:24
    |
-33 |     let my_frac_pi_6 = 0.523598775598;
+LL |     let my_frac_pi_6 = 0.523598775598;
    |                        ^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found. Consider using it directly
-  --> $DIR/approx_const.rs:36:24
+  --> $DIR/approx_const.rs:33:24
    |
-36 |     let my_frac_pi_8 = 0.3926990816987;
+LL |     let my_frac_pi_8 = 0.3926990816987;
    |                        ^^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::LN_10` found. Consider using it directly
-  --> $DIR/approx_const.rs:39:20
+  --> $DIR/approx_const.rs:36:20
    |
-39 |     let my_ln_10 = 2.302585092994046;
+LL |     let my_ln_10 = 2.302585092994046;
    |                    ^^^^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::LN_2` found. Consider using it directly
-  --> $DIR/approx_const.rs:42:19
+  --> $DIR/approx_const.rs:39:19
    |
-42 |     let my_ln_2 = 0.6931471805599453;
+LL |     let my_ln_2 = 0.6931471805599453;
    |                   ^^^^^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::LOG10_E` found. Consider using it directly
-  --> $DIR/approx_const.rs:45:22
+  --> $DIR/approx_const.rs:42:22
    |
-45 |     let my_log10_e = 0.4342944819032518;
+LL |     let my_log10_e = 0.4342944819032518;
    |                      ^^^^^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::LOG2_E` found. Consider using it directly
-  --> $DIR/approx_const.rs:48:21
+  --> $DIR/approx_const.rs:45:21
    |
-48 |     let my_log2_e = 1.4426950408889634;
+LL |     let my_log2_e = 1.4426950408889634;
    |                     ^^^^^^^^^^^^^^^^^^
 
 error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly
-  --> $DIR/approx_const.rs:51:17
+  --> $DIR/approx_const.rs:48:17
    |
-51 |     let my_pi = 3.1415;
+LL |     let my_pi = 3.1415;
    |                 ^^^^^^
 
 error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly
-  --> $DIR/approx_const.rs:52:21
+  --> $DIR/approx_const.rs:49:21
    |
-52 |     let almost_pi = 3.14;
+LL |     let almost_pi = 3.14;
    |                     ^^^^
 
 error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it directly
-  --> $DIR/approx_const.rs:55:18
+  --> $DIR/approx_const.rs:52:18
    |
-55 |     let my_sq2 = 1.4142;
+LL |     let my_sq2 = 1.4142;
    |                  ^^^^^^
 
 error: aborting due to 19 previous errors
index 7ed71b597074fec7767cc670f8b789f0a6c95668..c3cea99760683ccef2b4687eb2923c3e3a5c1004 100644 (file)
@@ -1,8 +1,13 @@
+#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)]
+#![allow(
+    unused,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
 
-
-
-#![warn(integer_arithmetic, float_arithmetic)]
-#![allow(unused, shadow_reuse, shadow_unrelated, no_effect, unnecessary_operation)]
+#[rustfmt::skip]
 fn main() {
     let i = 1i32;
     1 + i;
@@ -12,6 +17,10 @@ fn main() {
     i - 2 + 2 - i;
     -i;
 
+    // no error, overflows are checked by `overflowing_literals`
+    -1;
+    -(-1);
+
     i & 1; // no wrapping
     i | 1;
     i ^ 1;
@@ -27,4 +36,36 @@ fn main() {
     f / 2.0;
     f - 2.0 * 4.2;
     -f;
+
+    // No errors for the following items because they are constant expressions
+    enum Foo {
+        Bar = -2,
+    }
+    struct Baz([i32; 1 + 1]);
+    union Qux {
+        field: [i32; 1 + 1],
+    }
+    type Alias = [i32; 1 + 1];
+
+    const FOO: i32 = -2;
+    static BAR: i32 = -2;
+
+    let _: [i32; 1 + 1] = [0, 0];
+
+    let _: [i32; 1 + 1] = {
+        let a: [i32; 1 + 1] = [0, 0];
+        a
+    };
+
+    trait Trait {
+        const ASSOC: i32 = 1 + 1;
+    }
+
+    impl Trait for Foo {
+        const ASSOC: i32 = {
+            let _: [i32; 1 + 1];
+            fn foo() {}
+            1 + 1
+        };
+    }
 }
index ad4a02e219012c65a916b14139e91dd8a66f070e..b21efaa849f79e0f78d2c1018cee2182a8bb54b0 100644 (file)
@@ -1,72 +1,72 @@
 error: integer arithmetic detected
--> $DIR/arithmetic.rs:8:5
-  |
-8 |     1 + i;
-  |     ^^^^^
-  |
-  = note: `-D integer-arithmetic` implied by `-D warnings`
 --> $DIR/arithmetic.rs:13:5
+   |
+LL |     1 + i;
+   |     ^^^^^
+   |
+   = note: `-D clippy::integer-arithmetic` implied by `-D warnings`
 
 error: integer arithmetic detected
--> $DIR/arithmetic.rs:9:5
-  |
-9 |     i * 2;
-  |     ^^^^^
 --> $DIR/arithmetic.rs:14:5
+   |
+LL |     i * 2;
+   |     ^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/arithmetic.rs:10:5
+  --> $DIR/arithmetic.rs:15:5
    |
-10 | /     1 %
-11 | |     i / 2; // no error, this is part of the expression in the preceding line
+LL | /     1 %
+LL | |     i / 2; // no error, this is part of the expression in the preceding line
    | |_________^
 
 error: integer arithmetic detected
-  --> $DIR/arithmetic.rs:12:5
+  --> $DIR/arithmetic.rs:17:5
    |
-12 |     i - 2 + 2 - i;
+LL |     i - 2 + 2 - i;
    |     ^^^^^^^^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/arithmetic.rs:13:5
+  --> $DIR/arithmetic.rs:18:5
    |
-13 |     -i;
+LL |     -i;
    |     ^^
 
 error: floating-point arithmetic detected
-  --> $DIR/arithmetic.rs:23:5
+  --> $DIR/arithmetic.rs:32:5
    |
-23 |     f * 2.0;
+LL |     f * 2.0;
    |     ^^^^^^^
    |
-   = note: `-D float-arithmetic` implied by `-D warnings`
+   = note: `-D clippy::float-arithmetic` implied by `-D warnings`
 
 error: floating-point arithmetic detected
-  --> $DIR/arithmetic.rs:25:5
+  --> $DIR/arithmetic.rs:34:5
    |
-25 |     1.0 + f;
+LL |     1.0 + f;
    |     ^^^^^^^
 
 error: floating-point arithmetic detected
-  --> $DIR/arithmetic.rs:26:5
+  --> $DIR/arithmetic.rs:35:5
    |
-26 |     f * 2.0;
+LL |     f * 2.0;
    |     ^^^^^^^
 
 error: floating-point arithmetic detected
-  --> $DIR/arithmetic.rs:27:5
+  --> $DIR/arithmetic.rs:36:5
    |
-27 |     f / 2.0;
+LL |     f / 2.0;
    |     ^^^^^^^
 
 error: floating-point arithmetic detected
-  --> $DIR/arithmetic.rs:28:5
+  --> $DIR/arithmetic.rs:37:5
    |
-28 |     f - 2.0 * 4.2;
+LL |     f - 2.0 * 4.2;
    |     ^^^^^^^^^^^^^
 
 error: floating-point arithmetic detected
-  --> $DIR/arithmetic.rs:29:5
+  --> $DIR/arithmetic.rs:38:5
    |
-29 |     -f;
+LL |     -f;
    |     ^^
 
 error: aborting due to 11 previous errors
diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs
new file mode 100644 (file)
index 0000000..aee6cc5
--- /dev/null
@@ -0,0 +1,25 @@
+macro_rules! assert_const {
+    ($len:expr) => {
+        assert!($len > 0);
+        debug_assert!($len < 0);
+    };
+}
+
+fn main() {
+    assert!(true);
+    assert!(false);
+    assert!(true, "true message");
+    assert!(false, "false message");
+
+    const B: bool = true;
+    assert!(B);
+
+    const C: bool = false;
+    assert!(C);
+
+    debug_assert!(true);
+    // Don't lint this, since there is no better way for expressing "Only panic in debug mode".
+    debug_assert!(false); // #3948
+    assert_const!(3);
+    assert_const!(-1);
+}
diff --git a/tests/ui/assertions_on_constants.stderr b/tests/ui/assertions_on_constants.stderr
new file mode 100644 (file)
index 0000000..c22da85
--- /dev/null
@@ -0,0 +1,60 @@
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:9:5
+   |
+LL |     assert!(true);
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::assertions-on-constants` implied by `-D warnings`
+   = help: remove it
+
+error: `assert!(false)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:10:5
+   |
+LL |     assert!(false);
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!()` or `unreachable!()`
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:11:5
+   |
+LL |     assert!(true, "true message");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: `assert!(false)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:12:5
+   |
+LL |     assert!(false, "false message");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!()` or `unreachable!()`
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:15:5
+   |
+LL |     assert!(B);
+   |     ^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: `assert!(false)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:18:5
+   |
+LL |     assert!(C);
+   |     ^^^^^^^^^^^
+   |
+   = help: use `panic!()` or `unreachable!()`
+
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:20:5
+   |
+LL |     debug_assert!(true);
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: remove it
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to 7 previous errors
+
index 2b49f2146ba4d4e29296f38e7d63d1e26b43ad1b..c7b4865f5c2a7d350bfb888f0d42b4f0278301dc 100644 (file)
@@ -1,28 +1,6 @@
-
-
-
-#[warn(assign_ops)]
-#[allow(unused_assignments)]
-fn main() {
-    let mut i = 1i32;
-    i += 2;
-    i += 2 + 17;
-    i -= 6;
-    i -= 2 - 1;
-    i *= 5;
-    i *= 1+5;
-    i /= 32;
-    i /= 32 | 5;
-    i /= 32 / 5;
-    i %= 42;
-    i >>= i;
-    i <<= 9 + 6 - 7;
-    i += 1 << 5;
-}
-
 #[allow(dead_code, unused_assignments)]
-#[warn(assign_op_pattern)]
-fn bla() {
+#[warn(clippy::assign_op_pattern)]
+fn main() {
     let mut a = 5;
     a = a + 1;
     a = 1 + a;
index 2123507e2ef6dbded32d0f203517b93ba6bbe778..646f99701221743028b5b01b00553d4e53598676 100644 (file)
-error: assign operation detected
- --> $DIR/assign_ops.rs:8:5
-  |
-8 |     i += 2;
-  |     ^^^^^^ help: replace it with: `i = i + 2`
-  |
-  = note: `-D assign-ops` implied by `-D warnings`
-
-error: assign operation detected
- --> $DIR/assign_ops.rs:9:5
-  |
-9 |     i += 2 + 17;
-  |     ^^^^^^^^^^^ help: replace it with: `i = i + 2 + 17`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:10:5
-   |
-10 |     i -= 6;
-   |     ^^^^^^ help: replace it with: `i = i - 6`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:11:5
-   |
-11 |     i -= 2 - 1;
-   |     ^^^^^^^^^^ help: replace it with: `i = i - (2 - 1)`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:12:5
-   |
-12 |     i *= 5;
-   |     ^^^^^^ help: replace it with: `i = i * 5`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:13:5
-   |
-13 |     i *= 1+5;
-   |     ^^^^^^^^ help: replace it with: `i = i * (1+5)`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:14:5
-   |
-14 |     i /= 32;
-   |     ^^^^^^^ help: replace it with: `i = i / 32`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:15:5
-   |
-15 |     i /= 32 | 5;
-   |     ^^^^^^^^^^^ help: replace it with: `i = i / (32 | 5)`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:16:5
-   |
-16 |     i /= 32 / 5;
-   |     ^^^^^^^^^^^ help: replace it with: `i = i / (32 / 5)`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:17:5
-   |
-17 |     i %= 42;
-   |     ^^^^^^^ help: replace it with: `i = i % 42`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:18:5
-   |
-18 |     i >>= i;
-   |     ^^^^^^^ help: replace it with: `i = i >> i`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:19:5
-   |
-19 |     i <<= 9 + 6 - 7;
-   |     ^^^^^^^^^^^^^^^ help: replace it with: `i = i << (9 + 6 - 7)`
-
-error: assign operation detected
-  --> $DIR/assign_ops.rs:20:5
-   |
-20 |     i += 1 << 5;
-   |     ^^^^^^^^^^^ help: replace it with: `i = i + (1 << 5)`
-
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:27:5
+  --> $DIR/assign_ops.rs:5:5
    |
-27 |     a = a + 1;
+LL |     a = a + 1;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
    |
-   = note: `-D assign-op-pattern` implied by `-D warnings`
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:28:5
+  --> $DIR/assign_ops.rs:6:5
    |
-28 |     a = 1 + a;
+LL |     a = 1 + a;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:29:5
+  --> $DIR/assign_ops.rs:7:5
    |
-29 |     a = a - 1;
+LL |     a = a - 1;
    |     ^^^^^^^^^ help: replace it with: `a -= 1`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:30:5
+  --> $DIR/assign_ops.rs:8:5
    |
-30 |     a = a * 99;
+LL |     a = a * 99;
    |     ^^^^^^^^^^ help: replace it with: `a *= 99`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:31:5
+  --> $DIR/assign_ops.rs:9:5
    |
-31 |     a = 42 * a;
+LL |     a = 42 * a;
    |     ^^^^^^^^^^ help: replace it with: `a *= 42`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:32:5
+  --> $DIR/assign_ops.rs:10:5
    |
-32 |     a = a / 2;
+LL |     a = a / 2;
    |     ^^^^^^^^^ help: replace it with: `a /= 2`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:33:5
+  --> $DIR/assign_ops.rs:11:5
    |
-33 |     a = a % 5;
+LL |     a = a % 5;
    |     ^^^^^^^^^ help: replace it with: `a %= 5`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:34:5
+  --> $DIR/assign_ops.rs:12:5
    |
-34 |     a = a & 1;
+LL |     a = a & 1;
    |     ^^^^^^^^^ help: replace it with: `a &= 1`
 
 error: manual implementation of an assign operation
-  --> $DIR/assign_ops.rs:40:5
+  --> $DIR/assign_ops.rs:18:5
    |
-40 |     s = s + "bla";
+LL |     s = s + "bla";
    |     ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
 
-error: aborting due to 22 previous errors
+error: aborting due to 9 previous errors
 
index 2d3adc2a661f945822a7b8db423e923cc42a3f74..4703a8c77778857405266a60d5f20977e1bc59ef 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
 #[allow(unused_assignments)]
-#[warn(misrefactored_assign_op, assign_op_pattern)]
+#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
 fn main() {
     let mut a = 5;
     a += a + 1;
@@ -43,3 +40,16 @@ fn mul_assign(&mut self, rhs: i64) {
         *self = *self * rhs
     }
 }
+
+fn cow_add_assign() {
+    use std::borrow::Cow;
+    let mut buf = Cow::Owned(String::from("bar"));
+    let cows = Cow::Borrowed("foo");
+
+    // this can be linted
+    buf = buf + cows.clone();
+
+    // this should not as cow<str> Add is not commutative
+    buf = cows + buf;
+    println!("{}", buf);
+}
index 2858af1f8c0b5493291ec1943867d97ba23b19df..872d6e0d7347323960197ff301bb629c62d42a5e 100644 (file)
 error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:8:5
-  |
-8 |     a += a + 1;
-  |     ^^^^^^^^^^
-  |
-  = note: `-D misrefactored-assign-op` implied by `-D warnings`
 --> $DIR/assign_ops2.rs:5:5
+   |
+LL |     a += a + 1;
+   |     ^^^^^^^^^^
+   |
+   = note: `-D clippy::misrefactored-assign-op` implied by `-D warnings`
 help: Did you mean a = a + 1 or a = a + a + 1? Consider replacing it with
-  |
-8 |     a += 1;
-  |     ^^^^^^
+   |
+LL |     a += 1;
+   |     ^^^^^^
 help: or
-  |
-8 |     a = a + a + 1;
-  |     ^^^^^^^^^^^^^
+   |
+LL |     a = a + a + 1;
+   |     ^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
--> $DIR/assign_ops2.rs:9:5
-  |
-9 |     a += 1 + a;
-  |     ^^^^^^^^^^
 --> $DIR/assign_ops2.rs:6:5
+   |
+LL |     a += 1 + a;
+   |     ^^^^^^^^^^
 help: Did you mean a = a + 1 or a = a + 1 + a? Consider replacing it with
-  |
-9 |     a += 1;
-  |     ^^^^^^
+   |
+LL |     a += 1;
+   |     ^^^^^^
 help: or
-  |
-9 |     a = a + 1 + a;
-  |     ^^^^^^^^^^^^^
+   |
+LL |     a = a + 1 + a;
+   |     ^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:10:5
+  --> $DIR/assign_ops2.rs:7:5
    |
-10 |     a -= a - 1;
+LL |     a -= a - 1;
    |     ^^^^^^^^^^
 help: Did you mean a = a - 1 or a = a - (a - 1)? Consider replacing it with
    |
-10 |     a -= 1;
+LL |     a -= 1;
    |     ^^^^^^
 help: or
    |
-10 |     a = a - (a - 1);
+LL |     a = a - (a - 1);
    |     ^^^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:11:5
+  --> $DIR/assign_ops2.rs:8:5
    |
-11 |     a *= a * 99;
+LL |     a *= a * 99;
    |     ^^^^^^^^^^^
 help: Did you mean a = a * 99 or a = a * a * 99? Consider replacing it with
    |
-11 |     a *= 99;
+LL |     a *= 99;
    |     ^^^^^^^
 help: or
    |
-11 |     a = a * a * 99;
+LL |     a = a * a * 99;
    |     ^^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:12:5
+  --> $DIR/assign_ops2.rs:9:5
    |
-12 |     a *= 42 * a;
+LL |     a *= 42 * a;
    |     ^^^^^^^^^^^
 help: Did you mean a = a * 42 or a = a * 42 * a? Consider replacing it with
    |
-12 |     a *= 42;
+LL |     a *= 42;
    |     ^^^^^^^
 help: or
    |
-12 |     a = a * 42 * a;
+LL |     a = a * 42 * a;
    |     ^^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:13:5
+  --> $DIR/assign_ops2.rs:10:5
    |
-13 |     a /= a / 2;
+LL |     a /= a / 2;
    |     ^^^^^^^^^^
 help: Did you mean a = a / 2 or a = a / (a / 2)? Consider replacing it with
    |
-13 |     a /= 2;
+LL |     a /= 2;
    |     ^^^^^^
 help: or
    |
-13 |     a = a / (a / 2);
+LL |     a = a / (a / 2);
    |     ^^^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:14:5
+  --> $DIR/assign_ops2.rs:11:5
    |
-14 |     a %= a % 5;
+LL |     a %= a % 5;
    |     ^^^^^^^^^^
 help: Did you mean a = a % 5 or a = a % (a % 5)? Consider replacing it with
    |
-14 |     a %= 5;
+LL |     a %= 5;
    |     ^^^^^^
 help: or
    |
-14 |     a = a % (a % 5);
+LL |     a = a % (a % 5);
    |     ^^^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:15:5
+  --> $DIR/assign_ops2.rs:12:5
    |
-15 |     a &= a & 1;
+LL |     a &= a & 1;
    |     ^^^^^^^^^^
 help: Did you mean a = a & 1 or a = a & a & 1? Consider replacing it with
    |
-15 |     a &= 1;
+LL |     a &= 1;
    |     ^^^^^^
 help: or
    |
-15 |     a = a & a & 1;
+LL |     a = a & a & 1;
    |     ^^^^^^^^^^^^^
 
 error: variable appears on both sides of an assignment operation
-  --> $DIR/assign_ops2.rs:16:5
+  --> $DIR/assign_ops2.rs:13:5
    |
-16 |     a *= a * a;
+LL |     a *= a * a;
    |     ^^^^^^^^^^
 help: Did you mean a = a * a or a = a * a * a? Consider replacing it with
    |
-16 |     a *= a;
+LL |     a *= a;
    |     ^^^^^^
 help: or
    |
-16 |     a = a * a * a;
+LL |     a = a * a * a;
    |     ^^^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: manual implementation of an assign operation
+  --> $DIR/assign_ops2.rs:50:5
+   |
+LL |     buf = buf + cows.clone();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
+   |
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
+
+error: aborting due to 10 previous errors
 
index eb27b833aded0742735a78809017ddc4c31ba895..91b65a43be77fa5fdb3aa2a1fe66f2227347a7cf 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(inline_always, deprecated_semver)]
-
+#![warn(clippy::inline_always, clippy::deprecated_semver)]
+#![allow(clippy::assertions_on_constants)]
 #[inline(always)]
 fn test_attr_lint() {
     assert!(true)
@@ -20,22 +17,27 @@ fn false_positive_stmt() {
 
 #[inline(always)]
 fn empty_and_false_positive_stmt() {
-    ;
     unreachable!();
 }
 
 #[deprecated(since = "forever")]
-pub const SOME_CONST : u8 = 42;
+pub const SOME_CONST: u8 = 42;
 
 #[deprecated(since = "1")]
-pub const ANOTHER_CONST : u8 = 23;
+pub const ANOTHER_CONST: u8 = 23;
 
 #[deprecated(since = "0.1.1")]
-pub const YET_ANOTHER_CONST : u8 = 0;
+pub const YET_ANOTHER_CONST: u8 = 0;
 
 fn main() {
     test_attr_lint();
-    if false { false_positive_expr() }
-    if false { false_positive_stmt() }
-    if false { empty_and_false_positive_stmt() }
+    if false {
+        false_positive_expr()
+    }
+    if false {
+        false_positive_stmt()
+    }
+    if false {
+        empty_and_false_positive_stmt()
+    }
 }
index f743399a6069e341f3267fdb5ec0dbff7e784735..39ddf6f226d95482da927fb934b3973c79179892 100644 (file)
@@ -1,23 +1,23 @@
 error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
--> $DIR/attrs.rs:6:1
-  |
-6 | #[inline(always)]
-  | ^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D inline-always` implied by `-D warnings`
 --> $DIR/attrs.rs:3:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::inline-always` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:27:14
+  --> $DIR/attrs.rs:23:14
    |
-27 | #[deprecated(since = "forever")]
+LL | #[deprecated(since = "forever")]
    |              ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D deprecated-semver` implied by `-D warnings`
+   = note: `-D clippy::deprecated-semver` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:30:14
+  --> $DIR/attrs.rs:26:14
    |
-30 | #[deprecated(since = "1")]
+LL | #[deprecated(since = "1")]
    |              ^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
index eec26bcce3c8d57c053815b3353818b8a08caacf..0a1be35689670f3c024efdcf702479c474db547d 100644 (file)
@@ -1,7 +1,4 @@
-#![feature(tool_attributes)]
-
 fn main() {
-
     #[clippy::author]
     let x: char = 0x45 as char;
 }
index b06fb1d21e3512ed5749a290dfee9f0dde7df55b..1d7bf607a14687078e81773111fb51e70373ed26 100644 (file)
@@ -1,7 +1,6 @@
 if_chain! {
-    if let StmtKind::Decl(ref decl, _) = stmt.node
-    if let DeclKind::Local(ref local) = decl.node;
-    if let Some(ref init) = local.init
+    if let StmtKind::Local(ref local) = stmt.node;
+    if let Some(ref init) = local.init;
     if let ExprKind::Cast(ref expr, ref cast_ty) = init.node;
     if let TyKind::Path(ref qp) = cast_ty.node;
     if match_qpath(qp, &["char"]);
old mode 100755 (executable)
new mode 100644 (file)
index 8d08511..e99c3c4
@@ -1,5 +1,3 @@
-#![feature(tool_attributes)]
-
 fn main() {
     #[clippy::author]
     let _ = ::std::cmp::min(3, 4);
index 1c25708fb4849f734f6fc20a2dfec6d75e58bb0c..5c8c90c6b4c8f1bcd89b8e64b0b445e653be7ad9 100644 (file)
@@ -1,7 +1,6 @@
 if_chain! {
-    if let StmtKind::Decl(ref decl, _) = stmt.node
-    if let DeclKind::Local(ref local) = decl.node;
-    if let Some(ref init) = local.init
+    if let StmtKind::Local(ref local) = stmt.node;
+    if let Some(ref init) = local.init;
     if let ExprKind::Call(ref func, ref args) = init.node;
     if let ExprKind::Path(ref path) = func.node;
     if match_qpath(path, &["{{root}}", "std", "cmp", "min"]);
index 5faf440676d09444e0691bcc00b2e7ba5696acdf..b3dec876535c5e5e374f39baa5d6d89ba9535fad 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(tool_attributes)]
+#![feature(stmt_expr_attributes)]
 
 fn main() {
     #[clippy::author]
diff --git a/tests/ui/author/for_loop.stderr b/tests/ui/author/for_loop.stderr
new file mode 100644 (file)
index 0000000..e69de29
index b99e8e0ade5e5cb3247ef082f179e172acc4c6fa..a9651c2f718b1f2d09b740244459aebcf414024b 100644 (file)
@@ -1,10 +1,7 @@
 if_chain! {
-    if let ExprKind::Block(ref block) = expr.node;
-    if let StmtKind::Decl(ref decl, _) = block.node
-    if let DeclKind::Local(ref local) = decl.node;
-    if let Some(ref init) = local.init
-    if let ExprKind::Match(ref expr, ref arms, MatchSource::ForLoopDesugar) = init.node;
-    if let ExprKind::Call(ref func, ref args) = expr.node;
+    if let ExprKind::DropTemps(ref expr) = expr.node;
+    if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.node;
+    if let ExprKind::Call(ref func, ref args) = expr1.node;
     if let ExprKind::Path(ref path) = func.node;
     if match_qpath(path, &["{{root}}", "std", "iter", "IntoIterator", "into_iter"]);
     if args.len() == 1;
@@ -14,13 +11,12 @@ if_chain! {
     // unimplemented: field checks
     if arms.len() == 1;
     if let ExprKind::Loop(ref body, ref label, LoopSource::ForLoop) = arms[0].body.node;
-    if let StmtKind::Decl(ref decl1, _) = body.node
-    if let DeclKind::Local(ref local1) = decl1.node;
-    if let PatKind::Binding(BindingAnnotation::Mutable, _, name, None) = local1.pat.node;
+    if let StmtKind::Local(ref local) = body.node;
+    if let PatKind::Binding(BindingAnnotation::Mutable, _, name, None) = local.pat.node;
     if name.node.as_str() == "__next";
-    if let StmtKind::Expr(ref e, _) = local1.pat.node
-    if let ExprKind::Match(ref expr1, ref arms1, MatchSource::ForLoopDesugar) = e.node;
-    if let ExprKind::Call(ref func1, ref args1) = expr1.node;
+    if let StmtKind::Expr(ref e, _) = local.pat.node
+    if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.node;
+    if let ExprKind::Call(ref func1, ref args1) = expr2.node;
     if let ExprKind::Path(ref path2) = func1.node;
     if match_qpath(path2, &["{{root}}", "std", "iter", "Iterator", "next"]);
     if args1.len() == 1;
@@ -42,29 +38,23 @@ if_chain! {
     if arms1[1].pats.len() == 1;
     if let PatKind::Path(ref path7) = arms1[1].pats[0].node;
     if match_qpath(path7, &["{{root}}", "std", "option", "Option", "None"]);
-    if let StmtKind::Decl(ref decl2, _) = path7.node
-    if let DeclKind::Local(ref local2) = decl2.node;
-    if let Some(ref init1) = local2.init
-    if let ExprKind::Path(ref path8) = init1.node;
+    if let StmtKind::Local(ref local1) = path7.node;
+    if let Some(ref init) = local1.init;
+    if let ExprKind::Path(ref path8) = init.node;
     if match_qpath(path8, &["__next"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local2.pat.node;
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.node;
     if name1.node.as_str() == "y";
-    if let StmtKind::Expr(ref e1, _) = local2.pat.node
-    if let ExprKind::Block(ref block1) = e1.node;
-    if let StmtKind::Decl(ref decl3, _) = block1.node
-    if let DeclKind::Local(ref local3) = decl3.node;
-    if let Some(ref init2) = local3.init
-    if let ExprKind::Path(ref path9) = init2.node;
+    if let StmtKind::Expr(ref e1, _) = local1.pat.node
+    if let ExprKind::Block(ref block) = e1.node;
+    if let StmtKind::Local(ref local2) = block.node;
+    if let Some(ref init1) = local2.init;
+    if let ExprKind::Path(ref path9) = init1.node;
     if match_qpath(path9, &["y"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name2, None) = local3.pat.node;
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name2, None) = local2.pat.node;
     if name2.node.as_str() == "z";
     if arms[0].pats.len() == 1;
     if let PatKind::Binding(BindingAnnotation::Mutable, _, name3, None) = arms[0].pats[0].node;
     if name3.node.as_str() == "iter";
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name4, None) = local.pat.node;
-    if name4.node.as_str() == "_result";
-    if let ExprKind::Path(ref path10) = local.pat.node;
-    if match_qpath(path10, &["_result"]);
     then {
         // report your lint here
     }
diff --git a/tests/ui/author/if.rs b/tests/ui/author/if.rs
new file mode 100644 (file)
index 0000000..2e9cb14
--- /dev/null
@@ -0,0 +1,10 @@
+#[allow(clippy::all)]
+
+fn main() {
+    #[clippy::author]
+    let _ = if true {
+        1 == 1;
+    } else {
+        2 == 2;
+    };
+}
diff --git a/tests/ui/author/if.stderr b/tests/ui/author/if.stderr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/ui/author/if.stdout b/tests/ui/author/if.stdout
new file mode 100644 (file)
index 0000000..bff6546
--- /dev/null
@@ -0,0 +1,27 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.node;
+    if let Some(ref init) = local.init;
+    if let Some((ref cond, ref then, Some(else_))) = higher::if_block(&init);
+    if let ExprKind::Block(ref block) = else_.node;
+    if let StmtKind::Semi(ref e, _) = block.node
+    if let ExprKind::Binary(ref op, ref left, ref right) = e.node;
+    if BinOpKind::Eq == op.node;
+    if let ExprKind::Lit(ref lit) = left.node;
+    if let LitKind::Int(2, _) = lit.node;
+    if let ExprKind::Lit(ref lit1) = right.node;
+    if let LitKind::Int(2, _) = lit1.node;
+    if let ExprKind::Lit(ref lit2) = cond.node;
+    if let LitKind::Bool(true) = lit2.node;
+    if let ExprKind::Block(ref block1) = then.node;
+    if let StmtKind::Semi(ref e1, _) = block1.node
+    if let ExprKind::Binary(ref op1, ref left1, ref right1) = e1.node;
+    if BinOpKind::Eq == op1.node;
+    if let ExprKind::Lit(ref lit3) = left1.node;
+    if let LitKind::Int(1, _) = lit3.node;
+    if let ExprKind::Lit(ref lit4) = right1.node;
+    if let LitKind::Int(1, _) = lit4.node;
+    if let PatKind::Wild = local.pat.node;
+    then {
+        // report your lint here
+    }
+}
index c4f69b10df7e6d75ecc751d464b8d944eb2bab36..fa7e5cce43c22e4ad6e6a5fa75961f8d519c49a9 100644 (file)
@@ -1,15 +1,15 @@
 error: returning the result of a let binding from a block. Consider returning the expression directly.
- --> $DIR/matches.rs:9:13
-  |
-9 |             x
-  |             ^
-  |
-  = note: `-D let-and-return` implied by `-D warnings`
 --> $DIR/matches.rs:9:13
+   |
+LL |             x
+   |             ^
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
 note: this expression can be directly returned
- --> $DIR/matches.rs:8:21
-  |
-8 |             let x = 3;
-  |                     ^
 --> $DIR/matches.rs:8:21
+   |
+LL |             let x = 3;
+   |                     ^
 
 error: aborting due to previous error
 
index 94b25aefabed284196353925164afb34eb70e695..689ee695b60104efb9027da1554d6e4d6c5ebe79 100644 (file)
@@ -1,7 +1,7 @@
 if_chain! {
     if let StmtKind::Decl(ref decl, _) = stmt.node
     if let DeclKind::Local(ref local) = decl.node;
-    if let Some(ref init) = local.init
+    if let Some(ref init) = local.init;
     if let ExprKind::Match(ref expr, ref arms, MatchSource::Normal) = init.node;
     if let ExprKind::Lit(ref lit) = expr.node;
     if let LitKind::Int(42, _) = lit.node;
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
new file mode 100644 (file)
index 0000000..486e419
--- /dev/null
@@ -0,0 +1,9 @@
+#![allow(dead_code)]
+
+/// Used to test that certain lints don't trigger in imported external macros
+#[macro_export]
+macro_rules! foofoo {
+    () => {
+        loop {}
+    };
+}
diff --git a/tests/ui/auxiliary/option_helpers.rs b/tests/ui/auxiliary/option_helpers.rs
new file mode 100644 (file)
index 0000000..3319521
--- /dev/null
@@ -0,0 +1,47 @@
+#![allow(dead_code, unused_variables)]
+
+/// Utility macro to test linting behavior in `option_methods()`
+/// The lints included in `option_methods()` should not lint if the call to map is partially
+/// within a macro
+#[macro_export]
+macro_rules! opt_map {
+    ($opt:expr, $map:expr) => {
+        ($opt).map($map)
+    };
+}
+
+/// Struct to generate false positive for Iterator-based lints
+#[derive(Copy, Clone)]
+pub struct IteratorFalsePositives {
+    pub foo: u32,
+}
+
+impl IteratorFalsePositives {
+    pub fn filter(self) -> IteratorFalsePositives {
+        self
+    }
+
+    pub fn next(self) -> IteratorFalsePositives {
+        self
+    }
+
+    pub fn find(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn position(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn rposition(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn nth(self, n: usize) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    pub fn skip(self, _: usize) -> IteratorFalsePositives {
+        self
+    }
+}
diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs
new file mode 100644 (file)
index 0000000..08b9931
--- /dev/null
@@ -0,0 +1,22 @@
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_derive(DeriveSomething)]
+pub fn derive(_: TokenStream) -> TokenStream {
+    // Shound not trigger `used_underscore_binding`
+    let _inside_derive = 1;
+    assert_eq!(_inside_derive, _inside_derive);
+
+    let output = quote! {
+        // Should not trigger `useless_attribute`
+        #[allow(dead_code)]
+        extern crate clippy_lints;
+    };
+    output
+}
index 4843b4eba0d4a7ac16be529c1567402b55d88035..cfb493fb52afb4d1ad23b5b6d2a1cc1688ecb26f 100644 (file)
@@ -1,11 +1,13 @@
-
-
-
-const THREE_BITS : i64 = 7;
-const EVEN_MORE_REDIRECTION : i64 = THREE_BITS;
-
-#[warn(bad_bit_mask)]
-#[allow(ineffective_bit_mask, identity_op, no_effect, unnecessary_operation)]
+const THREE_BITS: i64 = 7;
+const EVEN_MORE_REDIRECTION: i64 = THREE_BITS;
+
+#[warn(clippy::bad_bit_mask)]
+#[allow(
+    clippy::ineffective_bit_mask,
+    clippy::identity_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
 fn main() {
     let x = 5;
 
@@ -44,8 +46,8 @@ fn main() {
     ineffective();
 }
 
-#[warn(ineffective_bit_mask)]
-#[allow(bad_bit_mask, no_effect, unnecessary_operation)]
+#[warn(clippy::ineffective_bit_mask)]
+#[allow(clippy::bad_bit_mask, clippy::no_effect, clippy::unnecessary_operation)]
 fn ineffective() {
     let x = 5;
 
index e1a4a42914c3730da92966e89ea33c63663730f4..159db0374d292fa056a1132ae026d153ce578dfe 100644 (file)
 error: &-masking with zero
-  --> $DIR/bit_masks.rs:12:5
+  --> $DIR/bit_masks.rs:14:5
    |
-12 |     x & 0 == 0;
+LL |     x & 0 == 0;
    |     ^^^^^^^^^^
    |
-   = note: `-D bad-bit-mask` implied by `-D warnings`
+   = note: `-D clippy::bad-bit-mask` implied by `-D warnings`
 
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/bit_masks.rs:12:5
+  --> $DIR/bit_masks.rs:14:5
    |
-12 |     x & 0 == 0;
+LL |     x & 0 == 0;
    |     ^^^^^
    |
-   = note: #[deny(erasing_op)] on by default
+   = note: #[deny(clippy::erasing_op)] on by default
 
 error: incompatible bit mask: `_ & 2` can never be equal to `1`
-  --> $DIR/bit_masks.rs:15:5
+  --> $DIR/bit_masks.rs:17:5
    |
-15 |     x & 2 == 1;
+LL |     x & 2 == 1;
    |     ^^^^^^^^^^
 
 error: incompatible bit mask: `_ | 3` can never be equal to `2`
-  --> $DIR/bit_masks.rs:19:5
+  --> $DIR/bit_masks.rs:21:5
    |
-19 |     x | 3 == 2;
+LL |     x | 3 == 2;
    |     ^^^^^^^^^^
 
 error: incompatible bit mask: `_ & 1` will never be higher than `1`
-  --> $DIR/bit_masks.rs:21:5
+  --> $DIR/bit_masks.rs:23:5
    |
-21 |     x & 1 > 1;
+LL |     x & 1 > 1;
    |     ^^^^^^^^^
 
 error: incompatible bit mask: `_ | 2` will always be higher than `1`
-  --> $DIR/bit_masks.rs:25:5
+  --> $DIR/bit_masks.rs:27:5
    |
-25 |     x | 2 > 1;
+LL |     x | 2 > 1;
    |     ^^^^^^^^^
 
 error: incompatible bit mask: `_ & 7` can never be equal to `8`
-  --> $DIR/bit_masks.rs:32:5
+  --> $DIR/bit_masks.rs:34:5
    |
-32 |     x & THREE_BITS == 8;
+LL |     x & THREE_BITS == 8;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: incompatible bit mask: `_ | 7` will never be lower than `7`
-  --> $DIR/bit_masks.rs:33:5
+  --> $DIR/bit_masks.rs:35:5
    |
-33 |     x | EVEN_MORE_REDIRECTION < 7;
+LL |     x | EVEN_MORE_REDIRECTION < 7;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: &-masking with zero
-  --> $DIR/bit_masks.rs:35:5
+  --> $DIR/bit_masks.rs:37:5
    |
-35 |     0 & x == 0;
+LL |     0 & x == 0;
    |     ^^^^^^^^^^
 
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/bit_masks.rs:35:5
+  --> $DIR/bit_masks.rs:37:5
    |
-35 |     0 & x == 0;
+LL |     0 & x == 0;
    |     ^^^^^
 
 error: incompatible bit mask: `_ | 2` will always be higher than `1`
-  --> $DIR/bit_masks.rs:39:5
+  --> $DIR/bit_masks.rs:41:5
    |
-39 |     1 < 2 | x;
+LL |     1 < 2 | x;
    |     ^^^^^^^^^
 
 error: incompatible bit mask: `_ | 3` can never be equal to `2`
-  --> $DIR/bit_masks.rs:40:5
+  --> $DIR/bit_masks.rs:42:5
    |
-40 |     2 == 3 | x;
+LL |     2 == 3 | x;
    |     ^^^^^^^^^^
 
 error: incompatible bit mask: `_ & 2` can never be equal to `1`
-  --> $DIR/bit_masks.rs:41:5
+  --> $DIR/bit_masks.rs:43:5
    |
-41 |     1 == x & 2;
+LL |     1 == x & 2;
    |     ^^^^^^^^^^
 
 error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly
-  --> $DIR/bit_masks.rs:52:5
+  --> $DIR/bit_masks.rs:54:5
    |
-52 |     x | 1 > 3;
+LL |     x | 1 > 3;
    |     ^^^^^^^^^
    |
-   = note: `-D ineffective-bit-mask` implied by `-D warnings`
+   = note: `-D clippy::ineffective-bit-mask` implied by `-D warnings`
 
 error: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared directly
-  --> $DIR/bit_masks.rs:53:5
+  --> $DIR/bit_masks.rs:55:5
    |
-53 |     x | 1 < 4;
+LL |     x | 1 < 4;
    |     ^^^^^^^^^
 
 error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly
-  --> $DIR/bit_masks.rs:54:5
+  --> $DIR/bit_masks.rs:56:5
    |
-54 |     x | 1 <= 3;
+LL |     x | 1 <= 3;
    |     ^^^^^^^^^^
 
 error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared directly
-  --> $DIR/bit_masks.rs:55:5
+  --> $DIR/bit_masks.rs:57:5
    |
-55 |     x | 1 >= 8;
+LL |     x | 1 >= 8;
    |     ^^^^^^^^^^
 
 error: aborting due to 17 previous errors
index 7baeb7bb75cbbc7d3d76a11e3a32f5ff0030c5af..ca9d8d16b787df5af6c08f834306dd49d9ed3cf2 100644 (file)
@@ -1,8 +1,12 @@
-
-
-
-#![allow(dead_code, similar_names, single_match, toplevel_ref_arg, unused_mut, unused_variables)]
-#![warn(blacklisted_name)]
+#![allow(
+    dead_code,
+    clippy::similar_names,
+    clippy::single_match,
+    clippy::toplevel_ref_arg,
+    unused_mut,
+    unused_variables
+)]
+#![warn(clippy::blacklisted_name)]
 
 fn test(foo: ()) {}
 
index 68fbe27a01eec0cf5c361e886d289e361c3d31b8..44123829fb0f651208a28aa35f981a94f42c99a5 100644 (file)
@@ -1,87 +1,87 @@
 error: use of a blacklisted/placeholder name `foo`
--> $DIR/blacklisted_name.rs:7:9
-  |
-7 | fn test(foo: ()) {}
-  |         ^^^
-  |
-  = note: `-D blacklisted-name` implied by `-D warnings`
 --> $DIR/blacklisted_name.rs:11:9
+   |
+LL | fn test(foo: ()) {}
+   |         ^^^
+   |
+   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:10:9
+  --> $DIR/blacklisted_name.rs:14:9
    |
-10 |     let foo = 42;
+LL |     let foo = 42;
    |         ^^^
 
 error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:11:9
+  --> $DIR/blacklisted_name.rs:15:9
    |
-11 |     let bar = 42;
+LL |     let bar = 42;
    |         ^^^
 
 error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:12:9
+  --> $DIR/blacklisted_name.rs:16:9
    |
-12 |     let baz = 42;
+LL |     let baz = 42;
    |         ^^^
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:18:10
+  --> $DIR/blacklisted_name.rs:22:10
    |
-18 |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(bar), baz @ Some(_)) => (),
    |          ^^^
 
 error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:18:20
+  --> $DIR/blacklisted_name.rs:22:20
    |
-18 |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(bar), baz @ Some(_)) => (),
    |                    ^^^
 
 error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:18:26
+  --> $DIR/blacklisted_name.rs:22:26
    |
-18 |         (foo, Some(bar), baz @ Some(_)) => (),
+LL |         (foo, Some(bar), baz @ Some(_)) => (),
    |                          ^^^
 
 error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:23:19
+  --> $DIR/blacklisted_name.rs:27:19
    |
-23 | fn issue_1647(mut foo: u8) {
+LL | fn issue_1647(mut foo: u8) {
    |                   ^^^
 
 error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:24:13
+  --> $DIR/blacklisted_name.rs:28:13
    |
-24 |     let mut bar = 0;
+LL |     let mut bar = 0;
    |             ^^^
 
 error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:25:21
+  --> $DIR/blacklisted_name.rs:29:21
    |
-25 |     if let Some(mut baz) = Some(42) {}
+LL |     if let Some(mut baz) = Some(42) {}
    |                     ^^^
 
 error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:29:13
+  --> $DIR/blacklisted_name.rs:33:13
    |
-29 |     let ref bar = 0;
+LL |     let ref bar = 0;
    |             ^^^
 
 error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:30:21
+  --> $DIR/blacklisted_name.rs:34:21
    |
-30 |     if let Some(ref baz) = Some(42) {}
+LL |     if let Some(ref baz) = Some(42) {}
    |                     ^^^
 
 error: use of a blacklisted/placeholder name `bar`
-  --> $DIR/blacklisted_name.rs:34:17
+  --> $DIR/blacklisted_name.rs:38:17
    |
-34 |     let ref mut bar = 0;
+LL |     let ref mut bar = 0;
    |                 ^^^
 
 error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:35:25
+  --> $DIR/blacklisted_name.rs:39:25
    |
-35 |     if let Some(ref mut baz) = Some(42) {}
+LL |     if let Some(ref mut baz) = Some(42) {}
    |                         ^^^
 
 error: aborting due to 14 previous errors
index 9e65a127af288dc76f40cf976e490e2ebc5eedfe..10342ed28b5757e94b2db10eb3a168fd878cd561 100644 (file)
@@ -1,29 +1,25 @@
-
-
-
-#![warn(block_in_if_condition_expr)]
-#![warn(block_in_if_condition_stmt)]
-#![allow(unused, let_and_return)]
-#![warn(nonminimal_bool)]
-
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![allow(unused, clippy::let_and_return)]
+#![warn(clippy::nonminimal_bool)]
 
 macro_rules! blocky {
-    () => {{true}}
+    () => {{
+        true
+    }};
 }
 
 macro_rules! blocky_too {
     () => {{
         let r = true;
         r
-    }}
+    }};
 }
 
 fn macro_if() {
-    if blocky!() {
-    }
+    if blocky!() {}
 
-    if blocky_too!() {
-    }
+    if blocky_too!() {}
 }
 
 fn condition_has_block() -> i32 {
@@ -45,21 +41,35 @@ fn condition_has_block_with_single_expression() -> i32 {
     }
 }
 
-fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val:T) -> bool {
+fn predicate<F: FnOnce(T) -> bool, T>(pfn: F, val: T) -> bool {
     pfn(val)
 }
 
 fn pred_test() {
     let v = 3;
     let sky = "blue";
-    // this is a sneaky case, where the block isn't directly in the condition, but is actually
-    // inside a closure that the condition is using.  same principle applies.  add some extra
-    // expressions to make sure linter isn't confused by them.
-    if v == 3 && sky == "blue" && predicate(|x| { let target = 3; x == target }, v) {
-    }
-
-    if predicate(|x| { let target = 3; x == target }, v) {
-    }
+    // This is a sneaky case, where the block isn't directly in the condition,
+    // but is actually nside a closure that the condition is using.
+    // The same principle applies -- add some extra expressions to make sure
+    // linter isn't confused by them.
+    if v == 3
+        && sky == "blue"
+        && predicate(
+            |x| {
+                let target = 3;
+                x == target
+            },
+            v,
+        )
+    {}
+
+    if predicate(
+        |x| {
+            let target = 3;
+            x == target
+        },
+        v,
+    ) {}
 }
 
 fn condition_is_normal() -> i32 {
@@ -72,9 +82,7 @@ fn condition_is_normal() -> i32 {
 }
 
 fn closure_without_block() {
-    if predicate(|x| x == 3, 6) {
-
-    }
+    if predicate(|x| x == 3, 6) {}
 }
 
 fn condition_is_unsafe_block() {
@@ -86,5 +94,12 @@ fn condition_is_unsafe_block() {
     }
 }
 
-fn main() {
+fn main() {}
+
+fn macro_in_closure() {
+    let option = Some(true);
+
+    if option.unwrap_or_else(|| unimplemented!()) {
+        unimplemented!()
+    }
 }
index 4b7d12598ecfa346dc411622215c115385a1ff3c..0876d5db6964152aa585e57f11f4210f90d47909 100644 (file)
@@ -1,14 +1,14 @@
 error: in an 'if' condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a 'let'
-  --> $DIR/block_in_if_condition.rs:30:8
+  --> $DIR/block_in_if_condition.rs:26:8
    |
-30 |       if {
+LL |       if {
    |  ________^
-31 | |         let x = 3;
-32 | |         x == 3
-33 | |     } {
+LL | |         let x = 3;
+LL | |         x == 3
+LL | |     } {
    | |_____^
    |
-   = note: `-D block-in-if-condition-stmt` implied by `-D warnings`
+   = note: `-D clippy::block-in-if-condition-stmt` implied by `-D warnings`
    = help: try
            let res = {
                let x = 3;
@@ -19,36 +19,44 @@ error: in an 'if' condition, avoid complex blocks or closures with blocks; inste
            } ... 
 
 error: omit braces around single expression condition
-  --> $DIR/block_in_if_condition.rs:41:8
+  --> $DIR/block_in_if_condition.rs:37:8
    |
-41 |     if { true } {
+LL |     if { true } {
    |        ^^^^^^^^
    |
-   = note: `-D block-in-if-condition-expr` implied by `-D warnings`
+   = note: `-D clippy::block-in-if-condition-expr` implied by `-D warnings`
    = help: try
            if true {
                6
            } ... 
 
 error: in an 'if' condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a 'let'
-  --> $DIR/block_in_if_condition.rs:58:49
-   |
-58 |     if v == 3 && sky == "blue" && predicate(|x| { let target = 3; x == target }, v) {
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/block_in_if_condition.rs:58:17
+   |
+LL |               |x| {
+   |  _________________^
+LL | |                 let target = 3;
+LL | |                 x == target
+LL | |             },
+   | |_____________^
 
 error: in an 'if' condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a 'let'
-  --> $DIR/block_in_if_condition.rs:61:22
-   |
-61 |     if predicate(|x| { let target = 3; x == target }, v) {
-   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/block_in_if_condition.rs:67:13
+   |
+LL |           |x| {
+   |  _____________^
+LL | |             let target = 3;
+LL | |             x == target
+LL | |         },
+   | |_________^
 
 error: this boolean expression can be simplified
-  --> $DIR/block_in_if_condition.rs:67:8
+  --> $DIR/block_in_if_condition.rs:77:8
    |
-67 |     if true && x == 3 {
+LL |     if true && x == 3 {
    |        ^^^^^^^^^^^^^^ help: try: `x == 3`
    |
-   = note: `-D nonminimal-bool` implied by `-D warnings`
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed
new file mode 100644 (file)
index 0000000..0bd73ec
--- /dev/null
@@ -0,0 +1,113 @@
+// run-rustfix
+
+#[warn(clippy::bool_comparison)]
+fn main() {
+    let x = true;
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x {
+        "yes"
+    } else {
+        "no"
+    };
+    if !x {
+        "yes"
+    } else {
+        "no"
+    };
+    let y = true;
+    if !x & y {
+        "yes"
+    } else {
+        "no"
+    };
+    if x & !y {
+        "yes"
+    } else {
+        "no"
+    };
+}
+
+#[allow(dead_code)]
+fn issue3703() {
+    struct Foo;
+    impl PartialEq<bool> for Foo {
+        fn eq(&self, _: &bool) -> bool {
+            true
+        }
+    }
+    impl PartialEq<Foo> for bool {
+        fn eq(&self, _: &Foo) -> bool {
+            true
+        }
+    }
+    impl PartialOrd<bool> for Foo {
+        fn partial_cmp(&self, _: &bool) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+    impl PartialOrd<Foo> for bool {
+        fn partial_cmp(&self, _: &Foo) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+
+    if Foo == true {}
+    if true == Foo {}
+    if Foo != true {}
+    if true != Foo {}
+    if Foo == false {}
+    if false == Foo {}
+    if Foo != false {}
+    if false != Foo {}
+    if Foo < false {}
+    if false < Foo {}
+}
index f05b9894fea0e7a21514f3b118e9dcf6be895706..74f504edfd0697054580db65500ea8b62e11c2b7 100644 (file)
+// run-rustfix
 
-
-
-#[warn(bool_comparison)]
+#[warn(clippy::bool_comparison)]
 fn main() {
     let x = true;
-    if x == true { "yes" } else { "no" };
-    if x == false { "yes" } else { "no" };
-    if true == x { "yes" } else { "no" };
-    if false == x { "yes" } else { "no" };
+    if x == true {
+        "yes"
+    } else {
+        "no"
+    };
+    if x == false {
+        "yes"
+    } else {
+        "no"
+    };
+    if true == x {
+        "yes"
+    } else {
+        "no"
+    };
+    if false == x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x != true {
+        "yes"
+    } else {
+        "no"
+    };
+    if x != false {
+        "yes"
+    } else {
+        "no"
+    };
+    if true != x {
+        "yes"
+    } else {
+        "no"
+    };
+    if false != x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x < true {
+        "yes"
+    } else {
+        "no"
+    };
+    if false < x {
+        "yes"
+    } else {
+        "no"
+    };
+    if x > false {
+        "yes"
+    } else {
+        "no"
+    };
+    if true > x {
+        "yes"
+    } else {
+        "no"
+    };
+    let y = true;
+    if x < y {
+        "yes"
+    } else {
+        "no"
+    };
+    if x > y {
+        "yes"
+    } else {
+        "no"
+    };
+}
+
+#[allow(dead_code)]
+fn issue3703() {
+    struct Foo;
+    impl PartialEq<bool> for Foo {
+        fn eq(&self, _: &bool) -> bool {
+            true
+        }
+    }
+    impl PartialEq<Foo> for bool {
+        fn eq(&self, _: &Foo) -> bool {
+            true
+        }
+    }
+    impl PartialOrd<bool> for Foo {
+        fn partial_cmp(&self, _: &bool) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+    impl PartialOrd<Foo> for bool {
+        fn partial_cmp(&self, _: &Foo) -> Option<std::cmp::Ordering> {
+            None
+        }
+    }
+
+    if Foo == true {}
+    if true == Foo {}
+    if Foo != true {}
+    if true != Foo {}
+    if Foo == false {}
+    if false == Foo {}
+    if Foo != false {}
+    if false != Foo {}
+    if Foo < false {}
+    if false < Foo {}
 }
index 4436980bc117fd222c98dbf99ef065c7de907b26..2aa070a00f30914e27a49e4a6a331343574cdb04 100644 (file)
@@ -1,28 +1,88 @@
 error: equality checks against true are unnecessary
--> $DIR/bool_comparison.rs:7:8
-  |
-7 |     if x == true { "yes" } else { "no" };
-  |        ^^^^^^^^^ help: try simplifying it as shown: `x`
-  |
-  = note: `-D bool-comparison` implied by `-D warnings`
 --> $DIR/bool_comparison.rs:6:8
+   |
+LL |     if x == true {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+   |
+   = note: `-D clippy::bool-comparison` implied by `-D warnings`
 
 error: equality checks against false can be replaced by a negation
--> $DIR/bool_comparison.rs:8:8
-  |
-8 |     if x == false { "yes" } else { "no" };
-  |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 --> $DIR/bool_comparison.rs:11:8
+   |
+LL |     if x == false {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: equality checks against true are unnecessary
--> $DIR/bool_comparison.rs:9:8
-  |
-9 |     if true == x { "yes" } else { "no" };
-  |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 --> $DIR/bool_comparison.rs:16:8
+   |
+LL |     if true == x {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/bool_comparison.rs:10:8
+  --> $DIR/bool_comparison.rs:21:8
    |
-10 |     if false == x { "yes" } else { "no" };
+LL |     if false == x {
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
-error: aborting due to 4 previous errors
+error: inequality checks against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:26:8
+   |
+LL |     if x != true {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: inequality checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:31:8
+   |
+LL |     if x != false {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: inequality checks against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:36:8
+   |
+LL |     if true != x {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: inequality checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:41:8
+   |
+LL |     if false != x {
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: less than comparison against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:46:8
+   |
+LL |     if x < true {
+   |        ^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: greater than checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:51:8
+   |
+LL |     if false < x {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: greater than checks against false are unnecessary
+  --> $DIR/bool_comparison.rs:56:8
+   |
+LL |     if x > false {
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: less than comparison against true can be replaced by a negation
+  --> $DIR/bool_comparison.rs:61:8
+   |
+LL |     if true > x {
+   |        ^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: order comparisons between booleans can be simplified
+  --> $DIR/bool_comparison.rs:67:8
+   |
+LL |     if x < y {
+   |        ^^^^^ help: try simplifying it as shown: `!x & y`
+
+error: order comparisons between booleans can be simplified
+  --> $DIR/bool_comparison.rs:72:8
+   |
+LL |     if x > y {
+   |        ^^^^^ help: try simplifying it as shown: `x & !y`
+
+error: aborting due to 14 previous errors
 
index fc16c12af28ac62beb0485b3e790df07559e4d43..c8e01d4b2587d964ef761c2c564dc96537bfbef6 100644 (file)
@@ -1,8 +1,6 @@
+#![warn(clippy::nonminimal_bool, clippy::logic_bug)]
 
-
-#![warn(nonminimal_bool, logic_bug)]
-
-#[allow(unused, many_single_char_names)]
+#[allow(unused, clippy::many_single_char_names)]
 fn main() {
     let a: bool = unimplemented!();
     let b: bool = unimplemented!();
@@ -23,7 +21,7 @@ fn main() {
     let _ = !(!a && b);
 }
 
-#[allow(unused, many_single_char_names)]
+#[allow(unused, clippy::many_single_char_names)]
 fn equality_stuff() {
     let a: i32 = unimplemented!();
     let b: i32 = unimplemented!();
@@ -39,7 +37,7 @@ fn equality_stuff() {
     let _ = a != b || !(a != b || c == d);
 }
 
-#[allow(unused, many_single_char_names)]
+#[allow(unused, clippy::many_single_char_names)]
 fn methods_with_negation() {
     let a: Option<i32> = unimplemented!();
     let b: Result<i32, i32> = unimplemented!();
@@ -58,64 +56,84 @@ fn methods_with_negation() {
     let _ = !c ^ c || !a.is_some();
 }
 
-// Simplified versions of https://github.com/rust-lang-nursery/rust-clippy/issues/2638
-// nonminimal_bool should only check the built-in Result and Some type, not
+// Simplified versions of https://github.com/rust-lang/rust-clippy/issues/2638
+// clippy::nonminimal_bool should only check the built-in Result and Some type, not
 // any other types like the following.
-enum CustomResultOk<E> { Ok, Err(E) }
-enum CustomResultErr<E> { Ok, Err(E) }
-enum CustomSomeSome<T> { Some(T), None }
-enum CustomSomeNone<T> { Some(T), None }
+enum CustomResultOk<E> {
+    Ok,
+    Err(E),
+}
+enum CustomResultErr<E> {
+    Ok,
+    Err(E),
+}
+enum CustomSomeSome<T> {
+    Some(T),
+    None,
+}
+enum CustomSomeNone<T> {
+    Some(T),
+    None,
+}
 
 impl<E> CustomResultOk<E> {
-    pub fn is_ok(&self) -> bool { true }
+    pub fn is_ok(&self) -> bool {
+        true
+    }
 }
 
 impl<E> CustomResultErr<E> {
-    pub fn is_err(&self) -> bool { true }
+    pub fn is_err(&self) -> bool {
+        true
+    }
 }
 
 impl<T> CustomSomeSome<T> {
-    pub fn is_some(&self) -> bool { true }
+    pub fn is_some(&self) -> bool {
+        true
+    }
 }
 
 impl<T> CustomSomeNone<T> {
-    pub fn is_none(&self) -> bool { true }
+    pub fn is_none(&self) -> bool {
+        true
+    }
 }
 
 fn dont_warn_for_custom_methods_with_negation() {
     let res = CustomResultOk::Err("Error");
     // Should not warn and suggest 'is_err()' because the type does not
     // implement is_err().
-    if !res.is_ok() { }
+    if !res.is_ok() {}
 
     let res = CustomResultErr::Err("Error");
     // Should not warn and suggest 'is_ok()' because the type does not
     // implement is_ok().
-    if !res.is_err() { }
+    if !res.is_err() {}
 
     let res = CustomSomeSome::Some("thing");
     // Should not warn and suggest 'is_none()' because the type does not
     // implement is_none().
-    if !res.is_some() { }
+    if !res.is_some() {}
 
     let res = CustomSomeNone::Some("thing");
     // Should not warn and suggest 'is_some()' because the type does not
     // implement is_some().
-    if !res.is_none() { }
+    if !res.is_none() {}
 }
 
 // Only Built-in Result and Some types should suggest the negated alternative
 fn warn_for_built_in_methods_with_negation() {
     let res: Result<usize, usize> = Ok(1);
-    if !res.is_ok() { }
-    if !res.is_err() { }
+    if !res.is_ok() {}
+    if !res.is_err() {}
 
     let res = Some(1);
-    if !res.is_some() { }
-    if !res.is_none() { }
+    if !res.is_some() {}
+    if !res.is_none() {}
 }
 
-#[allow(neg_cmp_op_on_partial_ord)]
+#[allow(clippy::neg_cmp_op_on_partial_ord)]
 fn dont_warn_for_negated_partial_ord_comparison() {
     let a: f64 = unimplemented!();
     let b: f64 = unimplemented!();
index f1996e8a26e462e6220d6f70f53a883d64ef3fc9..eebab8c3e25effb77f1c86142ac6dc9311e99ff9 100644 (file)
 error: this boolean expression contains a logic bug
-  --> $DIR/booleans.rs:12:13
+  --> $DIR/booleans.rs:10:13
    |
-12 |     let _ = a && b || a;
+LL |     let _ = a && b || a;
    |             ^^^^^^^^^^^ help: it would look like the following: `a`
    |
-   = note: `-D logic-bug` implied by `-D warnings`
+   = note: `-D clippy::logic-bug` implied by `-D warnings`
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/booleans.rs:12:18
+  --> $DIR/booleans.rs:10:18
    |
-12 |     let _ = a && b || a;
+LL |     let _ = a && b || a;
    |                  ^
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:14:13
+  --> $DIR/booleans.rs:12:13
    |
-14 |     let _ = !true;
+LL |     let _ = !true;
    |             ^^^^^ help: try: `false`
    |
-   = note: `-D nonminimal-bool` implied by `-D warnings`
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:15:13
+  --> $DIR/booleans.rs:13:13
    |
-15 |     let _ = !false;
+LL |     let _ = !false;
    |             ^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:16:13
+  --> $DIR/booleans.rs:14:13
    |
-16 |     let _ = !!a;
+LL |     let _ = !!a;
    |             ^^^ help: try: `a`
 
 error: this boolean expression contains a logic bug
-  --> $DIR/booleans.rs:17:13
+  --> $DIR/booleans.rs:15:13
    |
-17 |     let _ = false && a;
+LL |     let _ = false && a;
    |             ^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/booleans.rs:17:22
+  --> $DIR/booleans.rs:15:22
    |
-17 |     let _ = false && a;
+LL |     let _ = false && a;
    |                      ^
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:18:13
+  --> $DIR/booleans.rs:16:13
    |
-18 |     let _ = false || a;
+LL |     let _ = false || a;
    |             ^^^^^^^^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:23:13
+  --> $DIR/booleans.rs:21:13
    |
-23 |     let _ = !(!a && b);
+LL |     let _ = !(!a && b);
    |             ^^^^^^^^^^ help: try: `!b || a`
 
 error: this boolean expression contains a logic bug
-  --> $DIR/booleans.rs:33:13
+  --> $DIR/booleans.rs:31:13
    |
-33 |     let _ = a == b && a != b;
+LL |     let _ = a == b && a != b;
    |             ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/booleans.rs:33:13
+  --> $DIR/booleans.rs:31:13
    |
-33 |     let _ = a == b && a != b;
+LL |     let _ = a == b && a != b;
    |             ^^^^^^
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:34:13
+  --> $DIR/booleans.rs:32:13
    |
-34 |     let _ = a == b && c == 5 && a == b;
+LL |     let _ = a == b && c == 5 && a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: try
    |
-34 |     let _ = a == b && c == 5;
+LL |     let _ = a == b && c == 5;
    |             ^^^^^^^^^^^^^^^^
-34 |     let _ = !(c != 5 || a != b);
+LL |     let _ = !(c != 5 || a != b);
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:35:13
+  --> $DIR/booleans.rs:33:13
    |
-35 |     let _ = a == b && c == 5 && b == a;
+LL |     let _ = a == b && c == 5 && b == a;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: try
    |
-35 |     let _ = a == b && c == 5;
+LL |     let _ = a == b && c == 5;
    |             ^^^^^^^^^^^^^^^^
-35 |     let _ = !(c != 5 || a != b);
+LL |     let _ = !(c != 5 || a != b);
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: this boolean expression contains a logic bug
-  --> $DIR/booleans.rs:36:13
+  --> $DIR/booleans.rs:34:13
    |
-36 |     let _ = a < b && a >= b;
+LL |     let _ = a < b && a >= b;
    |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/booleans.rs:36:13
+  --> $DIR/booleans.rs:34:13
    |
-36 |     let _ = a < b && a >= b;
+LL |     let _ = a < b && a >= b;
    |             ^^^^^
 
 error: this boolean expression contains a logic bug
-  --> $DIR/booleans.rs:37:13
+  --> $DIR/booleans.rs:35:13
    |
-37 |     let _ = a > b && a <= b;
+LL |     let _ = a > b && a <= b;
    |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/booleans.rs:37:13
+  --> $DIR/booleans.rs:35:13
    |
-37 |     let _ = a > b && a <= b;
+LL |     let _ = a > b && a <= b;
    |             ^^^^^
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:39:13
+  --> $DIR/booleans.rs:37:13
    |
-39 |     let _ = a != b || !(a != b || c == d);
+LL |     let _ = a != b || !(a != b || c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: try
    |
-39 |     let _ = c != d || a != b;
+LL |     let _ = c != d || a != b;
    |             ^^^^^^^^^^^^^^^^
-39 |     let _ = !(a == b && c == d);
+LL |     let _ = !(a == b && c == d);
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:47:13
+  --> $DIR/booleans.rs:45:13
    |
-47 |     let _ = !a.is_some();
+LL |     let _ = !a.is_some();
    |             ^^^^^^^^^^^^ help: try: `a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:49:13
+  --> $DIR/booleans.rs:47:13
    |
-49 |     let _ = !a.is_none();
+LL |     let _ = !a.is_none();
    |             ^^^^^^^^^^^^ help: try: `a.is_some()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:51:13
+  --> $DIR/booleans.rs:49:13
    |
-51 |     let _ = !b.is_err();
+LL |     let _ = !b.is_err();
    |             ^^^^^^^^^^^ help: try: `b.is_ok()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:53:13
+  --> $DIR/booleans.rs:51:13
    |
-53 |     let _ = !b.is_ok();
+LL |     let _ = !b.is_ok();
    |             ^^^^^^^^^^ help: try: `b.is_err()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:55:13
+  --> $DIR/booleans.rs:53:13
    |
-55 |     let _ = !(a.is_some() && !c);
+LL |     let _ = !(a.is_some() && !c);
    |             ^^^^^^^^^^^^^^^^^^^^ help: try: `c || a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:56:13
+  --> $DIR/booleans.rs:54:13
    |
-56 |     let _ = !(!c ^ c) || !a.is_some();
+LL |     let _ = !(!c ^ c) || !a.is_some();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!(!c ^ c) || a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:57:13
+  --> $DIR/booleans.rs:55:13
    |
-57 |     let _ = (!c ^ c) || !a.is_some();
+LL |     let _ = (!c ^ c) || !a.is_some();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!c ^ c) || a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/booleans.rs:58:13
+  --> $DIR/booleans.rs:56:13
    |
-58 |     let _ = !c ^ c || !a.is_some();
+LL |     let _ = !c ^ c || !a.is_some();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `!c ^ c || a.is_none()`
 
 error: this boolean expression can be simplified
-   --> $DIR/booleans.rs:110:8
-    |
-110 |     if !res.is_ok() { }
-    |        ^^^^^^^^^^^^ help: try: `res.is_err()`
+  --> $DIR/booleans.rs:128:8
+   |
+LL |     if !res.is_ok() {}
+   |        ^^^^^^^^^^^^ help: try: `res.is_err()`
 
 error: this boolean expression can be simplified
-   --> $DIR/booleans.rs:111:8
-    |
-111 |     if !res.is_err() { }
-    |        ^^^^^^^^^^^^^ help: try: `res.is_ok()`
+  --> $DIR/booleans.rs:129:8
+   |
+LL |     if !res.is_err() {}
+   |        ^^^^^^^^^^^^^ help: try: `res.is_ok()`
 
 error: this boolean expression can be simplified
-   --> $DIR/booleans.rs:114:8
-    |
-114 |     if !res.is_some() { }
-    |        ^^^^^^^^^^^^^^ help: try: `res.is_none()`
+  --> $DIR/booleans.rs:132:8
+   |
+LL |     if !res.is_some() {}
+   |        ^^^^^^^^^^^^^^ help: try: `res.is_none()`
 
 error: this boolean expression can be simplified
-   --> $DIR/booleans.rs:115:8
-    |
-115 |     if !res.is_none() { }
-    |        ^^^^^^^^^^^^^^ help: try: `res.is_some()`
+  --> $DIR/booleans.rs:133:8
+   |
+LL |     if !res.is_none() {}
+   |        ^^^^^^^^^^^^^^ help: try: `res.is_some()`
 
 error: aborting due to 25 previous errors
 
index 394b810ed866fcc34c7f84fc30a1d40bd15a4c8d..3b53aab7e23f234650c6acafbf0c90903e3a8a19 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![deny(borrowed_box)]
-#![allow(blacklisted_name)]
+#![deny(clippy::borrowed_box)]
+#![allow(clippy::blacklisted_name)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
 
@@ -15,7 +12,7 @@ pub fn test2() {
 }
 
 struct Test3<'a> {
-    foo: &'a Box<bool>
+    foo: &'a Box<bool>,
 }
 
 trait Test4 {
@@ -39,7 +36,7 @@ pub fn test6() {
 }
 
 struct Test7<'a> {
-    foo: &'a Box<Any>
+    foo: &'a Box<Any>,
 }
 
 trait Test8 {
@@ -61,7 +58,7 @@ pub fn test10() {
 }
 
 struct Test11<'a> {
-    foo: &'a Box<Any + Send>
+    foo: &'a Box<Any + Send>,
 }
 
 trait Test12 {
@@ -74,7 +71,7 @@ fn test4(a: &Box<Any + 'static>) {
     }
 }
 
-fn main(){
+fn main() {
     test1(&mut Box::new(false));
     test2();
     test5(&mut (Box::new(false) as Box<Any>));
index 2cf0ea79626c91cc4d28aed099a2803c7f18996d..0cb455433c4219dddce5a4779bef2b4c64572d47 100644 (file)
@@ -1,31 +1,31 @@
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
--> $DIR/borrow_box.rs:9:19
-  |
-9 | pub fn test1(foo: &mut Box<bool>) {
-  |                   ^^^^^^^^^^^^^^ help: try: `&mut bool`
-  |
 --> $DIR/borrow_box.rs:6:19
+   |
+LL | pub fn test1(foo: &mut Box<bool>) {
+   |                   ^^^^^^^^^^^^^^ help: try: `&mut bool`
+   |
 note: lint level defined here
--> $DIR/borrow_box.rs:4:9
-  |
-4 | #![deny(borrowed_box)]
-  |         ^^^^^^^^^^^^
 --> $DIR/borrow_box.rs:1:9
+   |
+LL | #![deny(clippy::borrowed_box)]
+   |         ^^^^^^^^^^^^^^^^^^^^
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> $DIR/borrow_box.rs:14:14
+  --> $DIR/borrow_box.rs:11:14
    |
-14 |     let foo: &Box<bool>;
+LL |     let foo: &Box<bool>;
    |              ^^^^^^^^^^ help: try: `&bool`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> $DIR/borrow_box.rs:18:10
+  --> $DIR/borrow_box.rs:15:10
    |
-18 |     foo: &'a Box<bool>
+LL |     foo: &'a Box<bool>,
    |          ^^^^^^^^^^^^^ help: try: `&'a bool`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> $DIR/borrow_box.rs:22:17
+  --> $DIR/borrow_box.rs:19:17
    |
-22 |     fn test4(a: &Box<bool>);
+LL |     fn test4(a: &Box<bool>);
    |                 ^^^^^^^^^^ help: try: `&bool`
 
 error: aborting due to 4 previous errors
index 75b3b62643e8590e9a74c90858c66d7d42d73a5a..af3ba5b4d353415ce8c7bf711c7d720f0ff5198f 100644 (file)
@@ -1,14 +1,11 @@
-
-
-
-#![warn(clippy)]
-#![allow(boxed_local, needless_pass_by_value)]
-#![allow(blacklisted_name)]
+#![warn(clippy::all)]
+#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
+#![allow(clippy::blacklisted_name)]
 
 macro_rules! boxit {
     ($init:expr, $x:ty) => {
         let _: Box<$x> = Box::new($init);
-    }
+    };
 }
 
 fn test_macro() {
@@ -18,7 +15,8 @@ pub fn test(foo: Box<Vec<bool>>) {
     println!("{:?}", foo.get(0))
 }
 
-pub fn test2(foo: Box<Fn(Vec<u32>)>) { // pass if #31 is fixed
+pub fn test2(foo: Box<Fn(Vec<u32>)>) {
+    // pass if #31 is fixed
     foo(vec![1, 2, 3])
 }
 
@@ -26,7 +24,7 @@ pub fn test_local_not_linted() {
     let _: Box<Vec<bool>>;
 }
 
-fn main(){
+fn main() {
     test(Box::new(Vec::new()));
     test2(Box::new(|v| println!("{:?}", v)));
     test_macro();
index 254d07713862eb9515164423889bfbc775552e1b..fca12eddd573f04c1721bf2143d235ad2e3a06aa 100644 (file)
@@ -1,10 +1,10 @@
 error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`
-  --> $DIR/box_vec.rs:17:18
+  --> $DIR/box_vec.rs:14:18
    |
-17 | pub fn test(foo: Box<Vec<bool>>) {
+LL | pub fn test(foo: Box<Vec<bool>>) {
    |                  ^^^^^^^^^^^^^^
    |
-   = note: `-D box-vec` implied by `-D warnings`
+   = note: `-D clippy::box-vec` implied by `-D warnings`
    = help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.
 
 error: aborting due to previous error
index 4c4f5cbd3fe77ced71c03b8766e9490c9e2ef1d2..69b8b6a0e68c3af97530ff3316c953e96c2d4efc 100644 (file)
@@ -1,11 +1,9 @@
-
-
-#![warn(builtin_type_shadow)]
+#![warn(clippy::builtin_type_shadow)]
+#![allow(non_camel_case_types)]
 
 fn foo<u32>(a: u32) -> u32 {
     42
     // ^ rustc's type error
 }
 
-fn main() {
-}
+fn main() {}
index 5757a6ef3904ad08b553a2eab31fab87d9534196..5714f2094daad7cabc5460488754893bfc253209 100644 (file)
@@ -1,21 +1,21 @@
 error: This generic shadows the built-in type `u32`
--> $DIR/builtin-type-shadow.rs:5:8
-  |
-5 | fn foo<u32>(a: u32) -> u32 {
-  |        ^^^
-  |
-  = note: `-D builtin-type-shadow` implied by `-D warnings`
 --> $DIR/builtin-type-shadow.rs:4:8
+   |
+LL | fn foo<u32>(a: u32) -> u32 {
+   |        ^^^
+   |
+   = note: `-D clippy::builtin-type-shadow` implied by `-D warnings`
 
 error[E0308]: mismatched types
--> $DIR/builtin-type-shadow.rs:6:5
-  |
-5 | fn foo<u32>(a: u32) -> u32 {
-  |                        --- expected `u32` because of return type
-6 |     42
-  |     ^^ expected type parameter, found integral variable
-  |
-  = note: expected type `u32`
-             found type `{integer}`
 --> $DIR/builtin-type-shadow.rs:5:5
+   |
+LL | fn foo<u32>(a: u32) -> u32 {
+   |                        --- expected `u32` because of return type
+LL |     42
+   |     ^^ expected type parameter, found integer
+   |
+   = note: expected type `u32`
+              found type `{integer}`
 
 error: aborting due to 2 previous errors
 
index fc94667d968faf51637e54716f5be60995baf516..c724ee21be310b4a8d9d3376eeb36797304bcd65 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#[deny(naive_bytecount)]
+#[deny(clippy::naive_bytecount)]
 fn main() {
     let x = vec![0_u8; 16];
 
index 307edecfde1a097b5ed07b9536bc61f77b562213..43bc4b3c61e6435f9b77a9a504ea0af04c63146c 100644 (file)
@@ -1,25 +1,25 @@
 error: You appear to be counting bytes the naive way
--> $DIR/bytecount.rs:8:13
-  |
-8 |     let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
-  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)`
-  |
 --> $DIR/bytecount.rs:5:13
+   |
+LL |     let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, 0)`
+   |
 note: lint level defined here
--> $DIR/bytecount.rs:4:8
-  |
-4 | #[deny(naive_bytecount)]
-  |        ^^^^^^^^^^^^^^^
 --> $DIR/bytecount.rs:1:8
+   |
+LL | #[deny(clippy::naive_bytecount)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: You appear to be counting bytes the naive way
-  --> $DIR/bytecount.rs:10:13
+  --> $DIR/bytecount.rs:7:13
    |
-10 |     let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
+LL |     let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
 
 error: You appear to be counting bytes the naive way
-  --> $DIR/bytecount.rs:22:13
+  --> $DIR/bytecount.rs:19:13
    |
-22 |     let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
+LL |     let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)`
 
 error: aborting due to 3 previous errors
index 833e5a557807688408e27ff19f99af1e7d8e9e4d..16da099bd2115c3c7aac81bc6c46a6f01ae41b0a 100644 (file)
@@ -1,17 +1,23 @@
-
-
-
-#[warn(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap, cast_lossless)]
-#[allow(no_effect, unnecessary_operation)]
+#[warn(
+    clippy::cast_precision_loss,
+    clippy::cast_possible_truncation,
+    clippy::cast_sign_loss,
+    clippy::cast_possible_wrap
+)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
 fn main() {
-    // Test cast_precision_loss
-    1i32 as f32;
-    1i64 as f32;
-    1i64 as f64;
-    1u32 as f32;
-    1u64 as f32;
-    1u64 as f64;
-    // Test cast_possible_truncation
+    // Test clippy::cast_precision_loss
+    let x0 = 1i32;
+    x0 as f32;
+    let x1 = 1i64;
+    x1 as f32;
+    x1 as f64;
+    let x2 = 1u32;
+    x2 as f32;
+    let x3 = 1u64;
+    x3 as f32;
+    x3 as f64;
+    // Test clippy::cast_possible_truncation
     1f32 as i32;
     1f32 as u32;
     1f64 as f32;
@@ -19,26 +25,47 @@ fn main() {
     1i32 as u8;
     1f64 as isize;
     1f64 as usize;
-    // Test cast_possible_wrap
+    // Test clippy::cast_possible_wrap
     1u8 as i8;
     1u16 as i16;
     1u32 as i32;
     1u64 as i64;
     1usize as isize;
-    // Test cast_lossless with casts from floating-point types
-    1.0f32 as f64;
-    // Test cast_lossless with an expression wrapped in parens
-    (1u8 + 1u8) as u16;
-    // Test cast_sign_loss
+    // Test clippy::cast_sign_loss
     1i32 as u32;
+    -1i32 as u32;
     1isize as usize;
+    -1isize as usize;
+    0i8 as u8;
+    i8::max_value() as u8;
+    i16::max_value() as u16;
+    i32::max_value() as u32;
+    i64::max_value() as u64;
+    i128::max_value() as u128;
     // Extra checks for *size
     // Test cast_unnecessary
     1i32 as i32;
     1f32 as f32;
     false as bool;
     &1i32 as &i32;
+    // macro version
+    macro_rules! foo {
+        ($a:ident, $b:ident) => {
+            pub fn $a() -> $b {
+                1 as $b
+            }
+        };
+    }
+    foo!(a, i32);
+    foo!(b, f32);
+    foo!(c, f64);
+
+    // casting integer literal to float is unnecessary
+    100 as f32;
+    100 as f64;
+    100_i32 as f64;
     // Should not trigger
+    #[rustfmt::skip]
     let v = vec!(1);
     &v as &[i32];
     1.0 as f64;
index 0a008cb68bb3d0cd62f17dfb8a5d556b3966a867..42232808c9bc549130e96dc259b41f789466e21a 100644 (file)
 error: casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast.rs:8:5
-  |
-8 |     1i32 as f32;
-  |     ^^^^^^^^^^^
-  |
-  = note: `-D cast-precision-loss` implied by `-D warnings`
 --> $DIR/cast.rs:11:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
 
 error: casting i64 to f32 causes a loss of precision (i64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast.rs:9:5
-  |
-9 |     1i64 as f32;
-  |     ^^^^^^^^^^^
 --> $DIR/cast.rs:13:5
+   |
+LL |     x1 as f32;
+   |     ^^^^^^^^^
 
 error: casting i64 to f64 causes a loss of precision (i64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
-  --> $DIR/cast.rs:10:5
+  --> $DIR/cast.rs:14:5
    |
-10 |     1i64 as f64;
-   |     ^^^^^^^^^^^
+LL |     x1 as f64;
+   |     ^^^^^^^^^
 
 error: casting u32 to f32 causes a loss of precision (u32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
-  --> $DIR/cast.rs:11:5
+  --> $DIR/cast.rs:16:5
    |
-11 |     1u32 as f32;
-   |     ^^^^^^^^^^^
+LL |     x2 as f32;
+   |     ^^^^^^^^^
 
 error: casting u64 to f32 causes a loss of precision (u64 is 64 bits wide, but f32's mantissa is only 23 bits wide)
-  --> $DIR/cast.rs:12:5
+  --> $DIR/cast.rs:18:5
    |
-12 |     1u64 as f32;
-   |     ^^^^^^^^^^^
+LL |     x3 as f32;
+   |     ^^^^^^^^^
 
 error: casting u64 to f64 causes a loss of precision (u64 is 64 bits wide, but f64's mantissa is only 52 bits wide)
-  --> $DIR/cast.rs:13:5
+  --> $DIR/cast.rs:19:5
    |
-13 |     1u64 as f64;
-   |     ^^^^^^^^^^^
+LL |     x3 as f64;
+   |     ^^^^^^^^^
 
 error: casting f32 to i32 may truncate the value
-  --> $DIR/cast.rs:15:5
+  --> $DIR/cast.rs:21:5
    |
-15 |     1f32 as i32;
+LL |     1f32 as i32;
    |     ^^^^^^^^^^^
    |
-   = note: `-D cast-possible-truncation` implied by `-D warnings`
+   = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
 
 error: casting f32 to u32 may truncate the value
-  --> $DIR/cast.rs:16:5
+  --> $DIR/cast.rs:22:5
    |
-16 |     1f32 as u32;
+LL |     1f32 as u32;
    |     ^^^^^^^^^^^
 
 error: casting f32 to u32 may lose the sign of the value
-  --> $DIR/cast.rs:16:5
+  --> $DIR/cast.rs:22:5
    |
-16 |     1f32 as u32;
+LL |     1f32 as u32;
    |     ^^^^^^^^^^^
    |
-   = note: `-D cast-sign-loss` implied by `-D warnings`
+   = note: `-D clippy::cast-sign-loss` implied by `-D warnings`
 
 error: casting f64 to f32 may truncate the value
-  --> $DIR/cast.rs:17:5
+  --> $DIR/cast.rs:23:5
    |
-17 |     1f64 as f32;
+LL |     1f64 as f32;
    |     ^^^^^^^^^^^
 
 error: casting i32 to i8 may truncate the value
-  --> $DIR/cast.rs:18:5
-   |
-18 |     1i32 as i8;
-   |     ^^^^^^^^^^
-
-error: casting i32 to u8 may lose the sign of the value
-  --> $DIR/cast.rs:19:5
+  --> $DIR/cast.rs:24:5
    |
-19 |     1i32 as u8;
+LL |     1i32 as i8;
    |     ^^^^^^^^^^
 
 error: casting i32 to u8 may truncate the value
-  --> $DIR/cast.rs:19:5
+  --> $DIR/cast.rs:25:5
    |
-19 |     1i32 as u8;
+LL |     1i32 as u8;
    |     ^^^^^^^^^^
 
 error: casting f64 to isize may truncate the value
-  --> $DIR/cast.rs:20:5
+  --> $DIR/cast.rs:26:5
    |
-20 |     1f64 as isize;
+LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting f64 to usize may truncate the value
-  --> $DIR/cast.rs:21:5
+  --> $DIR/cast.rs:27:5
    |
-21 |     1f64 as usize;
+LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting f64 to usize may lose the sign of the value
-  --> $DIR/cast.rs:21:5
+  --> $DIR/cast.rs:27:5
    |
-21 |     1f64 as usize;
+LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting u8 to i8 may wrap around the value
-  --> $DIR/cast.rs:23:5
+  --> $DIR/cast.rs:29:5
    |
-23 |     1u8 as i8;
+LL |     1u8 as i8;
    |     ^^^^^^^^^
    |
-   = note: `-D cast-possible-wrap` implied by `-D warnings`
+   = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
 
 error: casting u16 to i16 may wrap around the value
-  --> $DIR/cast.rs:24:5
+  --> $DIR/cast.rs:30:5
    |
-24 |     1u16 as i16;
+LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting u32 to i32 may wrap around the value
-  --> $DIR/cast.rs:25:5
+  --> $DIR/cast.rs:31:5
    |
-25 |     1u32 as i32;
+LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting u64 to i64 may wrap around the value
-  --> $DIR/cast.rs:26:5
+  --> $DIR/cast.rs:32:5
    |
-26 |     1u64 as i64;
+LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting usize to isize may wrap around the value
-  --> $DIR/cast.rs:27:5
+  --> $DIR/cast.rs:33:5
    |
-27 |     1usize as isize;
+LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
-error: casting f32 to f64 may become silently lossy if types change
-  --> $DIR/cast.rs:29:5
-   |
-29 |     1.0f32 as f64;
-   |     ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
-   |
-   = note: `-D cast-lossless` implied by `-D warnings`
-
-error: casting u8 to u16 may become silently lossy if types change
-  --> $DIR/cast.rs:31:5
-   |
-31 |     (1u8 + 1u8) as u16;
-   |     ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)`
-
 error: casting i32 to u32 may lose the sign of the value
-  --> $DIR/cast.rs:33:5
+  --> $DIR/cast.rs:36:5
    |
-33 |     1i32 as u32;
-   |     ^^^^^^^^^^^
+LL |     -1i32 as u32;
+   |     ^^^^^^^^^^^^
 
 error: casting isize to usize may lose the sign of the value
-  --> $DIR/cast.rs:34:5
+  --> $DIR/cast.rs:38:5
    |
-34 |     1isize as usize;
-   |     ^^^^^^^^^^^^^^^
+LL |     -1isize as usize;
+   |     ^^^^^^^^^^^^^^^^
 
 error: casting to the same type is unnecessary (`i32` -> `i32`)
-  --> $DIR/cast.rs:37:5
+  --> $DIR/cast.rs:47:5
    |
-37 |     1i32 as i32;
+LL |     1i32 as i32;
    |     ^^^^^^^^^^^
    |
-   = note: `-D unnecessary-cast` implied by `-D warnings`
+   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting to the same type is unnecessary (`f32` -> `f32`)
-  --> $DIR/cast.rs:38:5
+  --> $DIR/cast.rs:48:5
    |
-38 |     1f32 as f32;
+LL |     1f32 as f32;
    |     ^^^^^^^^^^^
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> $DIR/cast.rs:39:5
+  --> $DIR/cast.rs:49:5
    |
-39 |     false as bool;
+LL |     false as bool;
    |     ^^^^^^^^^^^^^
 
+error: casting integer literal to f32 is unnecessary
+  --> $DIR/cast.rs:64:5
+   |
+LL |     100 as f32;
+   |     ^^^^^^^^^^ help: try: `100_f32`
+
+error: casting integer literal to f64 is unnecessary
+  --> $DIR/cast.rs:65:5
+   |
+LL |     100 as f64;
+   |     ^^^^^^^^^^ help: try: `100_f64`
+
+error: casting integer literal to f64 is unnecessary
+  --> $DIR/cast.rs:66:5
+   |
+LL |     100_i32 as f64;
+   |     ^^^^^^^^^^^^^^ help: try: `100_f64`
+
 error: aborting due to 28 previous errors
 
index 32e2f93169e2385a1b00b3e7e0c96f7c1ce81654..08450ba117645b67b0f17d4845deded8762e9b55 100644 (file)
@@ -1,11 +1,10 @@
 //! Test casts for alignment issues
 
-#![feature(libc)]
-
+#![feature(rustc_private)]
 extern crate libc;
 
-#[warn(cast_ptr_alignment)]
-#[allow(no_effect, unnecessary_operation, cast_lossless)]
+#[warn(clippy::cast_ptr_alignment)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
 fn main() {
     /* These should be warned against */
 
@@ -13,7 +12,7 @@ fn main() {
     (&1u8 as *const u8) as *const u16;
     (&mut 1u8 as *mut u8) as *mut u16;
 
-    /* These should be okay */
+    /* These should be ok */
 
     // not a pointer type
     1u8 as u16;
index 42df78a37a68eb89aead1759891f0d7f5534eb58..0077be1b570927326e97ae3412b1a4ce263fbe08 100644 (file)
@@ -1,15 +1,15 @@
 error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`)
-  --> $DIR/cast_alignment.rs:13:5
+  --> $DIR/cast_alignment.rs:12:5
    |
-13 |     (&1u8 as *const u8) as *const u16;
+LL |     (&1u8 as *const u8) as *const u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D cast-ptr-alignment` implied by `-D warnings`
+   = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings`
 
 error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`)
-  --> $DIR/cast_alignment.rs:14:5
+  --> $DIR/cast_alignment.rs:13:5
    |
-14 |     (&mut 1u8 as *mut u8) as *mut u16;
+LL |     (&mut 1u8 as *mut u8) as *mut u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/cast_lossless_float.fixed b/tests/ui/cast_lossless_float.fixed
new file mode 100644 (file)
index 0000000..8021dc2
--- /dev/null
@@ -0,0 +1,34 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+    // Test clippy::cast_lossless with casts to floating-point types
+    let x0 = 1i8;
+    f32::from(x0);
+    f64::from(x0);
+    let x1 = 1u8;
+    f32::from(x1);
+    f64::from(x1);
+    let x2 = 1i16;
+    f32::from(x2);
+    f64::from(x2);
+    let x3 = 1u16;
+    f32::from(x3);
+    f64::from(x3);
+    let x4 = 1i32;
+    f64::from(x4);
+    let x5 = 1u32;
+    f64::from(x5);
+
+    // Test with casts from floating-point types
+    f64::from(1.0f32);
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: f32) -> f64 {
+    input as f64
+}
index 9e61059b630c56af76c8a01f87f9ca984c283485..3cd5ad62203695aa8e5ada74e17f0dcedf8deb19 100644 (file)
@@ -1,15 +1,34 @@
-#[warn(cast_lossless)]
-#[allow(no_effect, unnecessary_operation)]
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
 fn main() {
-    // Test cast_lossless with casts to floating-point types
-    1i8 as f32;
-    1i8 as f64;
-    1u8 as f32;
-    1u8 as f64;
-    1i16 as f32;
-    1i16 as f64;
-    1u16 as f32;
-    1u16 as f64;
-    1i32 as f64;
-    1u32 as f64;
+    // Test clippy::cast_lossless with casts to floating-point types
+    let x0 = 1i8;
+    x0 as f32;
+    x0 as f64;
+    let x1 = 1u8;
+    x1 as f32;
+    x1 as f64;
+    let x2 = 1i16;
+    x2 as f32;
+    x2 as f64;
+    let x3 = 1u16;
+    x3 as f32;
+    x3 as f64;
+    let x4 = 1i32;
+    x4 as f64;
+    let x5 = 1u32;
+    x5 as f64;
+
+    // Test with casts from floating-point types
+    1.0f32 as f64;
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: f32) -> f64 {
+    input as f64
 }
index a60f838fae86b2485ef05112eff8772526b3e686..778a17344e532818ec76aca494839933db3972af 100644 (file)
@@ -1,64 +1,70 @@
-error: casting i8 to f32 may become silently lossy if types change
--> $DIR/cast_lossless_float.rs:5:5
-  |
-5 |     1i8 as f32;
-  |     ^^^^^^^^^^ help: try: `f32::from(1i8)`
-  |
-  = note: `-D cast-lossless` implied by `-D warnings`
+error: casting i8 to f32 may become silently lossy if you later change the type
 --> $DIR/cast_lossless_float.rs:9:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x0)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
 
-error: casting i8 to f64 may become silently lossy if types change
- --> $DIR/cast_lossless_float.rs:6:5
-  |
-6 |     1i8 as f64;
-  |     ^^^^^^^^^^ help: try: `f64::from(1i8)`
+error: casting i8 to f64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:10:5
+   |
+LL |     x0 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x0)`
+
+error: casting u8 to f32 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:12:5
+   |
+LL |     x1 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x1)`
 
-error: casting u8 to f32 may become silently lossy if types change
--> $DIR/cast_lossless_float.rs:7:5
-  |
-7 |     1u8 as f32;
-  |     ^^^^^^^^^^ help: try: `f32::from(1u8)`
+error: casting u8 to f64 may become silently lossy if you later change the type
 --> $DIR/cast_lossless_float.rs:13:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x1)`
 
-error: casting u8 to f64 may become silently lossy if types change
--> $DIR/cast_lossless_float.rs:8:5
-  |
-8 |     1u8 as f64;
-  |     ^^^^^^^^^^ help: try: `f64::from(1u8)`
+error: casting i16 to f32 may become silently lossy if you later change the type
 --> $DIR/cast_lossless_float.rs:15:5
+   |
+LL |     x2 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x2)`
 
-error: casting i16 to f32 may become silently lossy if types change
--> $DIR/cast_lossless_float.rs:9:5
-  |
-9 |     1i16 as f32;
-  |     ^^^^^^^^^^^ help: try: `f32::from(1i16)`
+error: casting i16 to f64 may become silently lossy if you later change the type
 --> $DIR/cast_lossless_float.rs:16:5
+   |
+LL |     x2 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x2)`
 
-error: casting i16 to f64 may become silently lossy if types change
-  --> $DIR/cast_lossless_float.rs:10:5
+error: casting u16 to f32 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:18:5
    |
-10 |     1i16 as f64;
-   |     ^^^^^^^^^^^ help: try: `f64::from(1i16)`
+LL |     x3 as f32;
+   |     ^^^^^^^^^ help: try: `f32::from(x3)`
 
-error: casting u16 to f32 may become silently lossy if types change
-  --> $DIR/cast_lossless_float.rs:11:5
+error: casting u16 to f64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:19:5
    |
-11 |     1u16 as f32;
-   |     ^^^^^^^^^^^ help: try: `f32::from(1u16)`
+LL |     x3 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x3)`
 
-error: casting u16 to f64 may become silently lossy if types change
-  --> $DIR/cast_lossless_float.rs:12:5
+error: casting i32 to f64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:21:5
    |
-12 |     1u16 as f64;
-   |     ^^^^^^^^^^^ help: try: `f64::from(1u16)`
+LL |     x4 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x4)`
 
-error: casting i32 to f64 may become silently lossy if types change
-  --> $DIR/cast_lossless_float.rs:13:5
+error: casting u32 to f64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:23:5
    |
-13 |     1i32 as f64;
-   |     ^^^^^^^^^^^ help: try: `f64::from(1i32)`
+LL |     x5 as f64;
+   |     ^^^^^^^^^ help: try: `f64::from(x5)`
 
-error: casting u32 to f64 may become silently lossy if types change
-  --> $DIR/cast_lossless_float.rs:14:5
+error: casting f32 to f64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_float.rs:26:5
    |
-14 |     1u32 as f64;
-   |     ^^^^^^^^^^^ help: try: `f64::from(1u32)`
+LL |     1.0f32 as f64;
+   |     ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
 
-error: aborting due to 10 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed
new file mode 100644 (file)
index 0000000..22936e4
--- /dev/null
@@ -0,0 +1,36 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
+
+fn main() {
+    // Test clippy::cast_lossless with casts to integer types
+    i16::from(1i8);
+    i32::from(1i8);
+    i64::from(1i8);
+    i16::from(1u8);
+    i32::from(1u8);
+    i64::from(1u8);
+    u16::from(1u8);
+    u32::from(1u8);
+    u64::from(1u8);
+    i32::from(1i16);
+    i64::from(1i16);
+    i32::from(1u16);
+    i64::from(1u16);
+    u32::from(1u16);
+    u64::from(1u16);
+    i64::from(1i32);
+    i64::from(1u32);
+    u64::from(1u32);
+
+    // Test with an expression wrapped in parens
+    u16::from(1u8 + 1u8);
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: u16) -> u32 {
+    input as u32
+}
index 5f89d057c3325dab9ed49049d1f3052c7f73253d..958a336cf2cd59b0255f13c207170b0f7524fb63 100644 (file)
@@ -1,8 +1,10 @@
+// run-rustfix
+
+#![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
+#![warn(clippy::cast_lossless)]
 
-#[warn(cast_lossless)]
-#[allow(no_effect, unnecessary_operation)]
 fn main() {
-    // Test cast_lossless with casts to integer types
+    // Test clippy::cast_lossless with casts to integer types
     1i8 as i16;
     1i8 as i32;
     1i8 as i64;
@@ -21,4 +23,14 @@ fn main() {
     1i32 as i64;
     1u32 as i64;
     1u32 as u64;
+
+    // Test with an expression wrapped in parens
+    (1u8 + 1u8) as u16;
+}
+
+// The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
+// so we skip the lint if the expression is in a const fn.
+// See #3656
+const fn abc(input: u16) -> u32 {
+    input as u32
 }
index 19d6176193c76fb681f92b186820cd1bb1eaa87d..c2f937942a3dea64e4dd2ed98cbf0f39a99dbe91 100644 (file)
-error: casting i8 to i16 may become silently lossy if types change
- --> $DIR/cast_lossless_integer.rs:6:5
-  |
-6 |     1i8 as i16;
-  |     ^^^^^^^^^^ help: try: `i16::from(1i8)`
-  |
-  = note: `-D cast-lossless` implied by `-D warnings`
-
-error: casting i8 to i32 may become silently lossy if types change
- --> $DIR/cast_lossless_integer.rs:7:5
-  |
-7 |     1i8 as i32;
-  |     ^^^^^^^^^^ help: try: `i32::from(1i8)`
-
-error: casting i8 to i64 may become silently lossy if types change
- --> $DIR/cast_lossless_integer.rs:8:5
-  |
-8 |     1i8 as i64;
-  |     ^^^^^^^^^^ help: try: `i64::from(1i8)`
-
-error: casting u8 to i16 may become silently lossy if types change
- --> $DIR/cast_lossless_integer.rs:9:5
-  |
-9 |     1u8 as i16;
-  |     ^^^^^^^^^^ help: try: `i16::from(1u8)`
-
-error: casting u8 to i32 may become silently lossy if types change
+error: casting i8 to i16 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:8:5
+   |
+LL |     1i8 as i16;
+   |     ^^^^^^^^^^ help: try: `i16::from(1i8)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
+
+error: casting i8 to i32 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:9:5
+   |
+LL |     1i8 as i32;
+   |     ^^^^^^^^^^ help: try: `i32::from(1i8)`
+
+error: casting i8 to i64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:10:5
    |
-10 |     1u8 as i32;
-   |     ^^^^^^^^^^ help: try: `i32::from(1u8)`
+LL |     1i8 as i64;
+   |     ^^^^^^^^^^ help: try: `i64::from(1i8)`
 
-error: casting u8 to i64 may become silently lossy if types change
+error: casting u8 to i16 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:11:5
    |
-11 |     1u8 as i64;
-   |     ^^^^^^^^^^ help: try: `i64::from(1u8)`
+LL |     1u8 as i16;
+   |     ^^^^^^^^^^ help: try: `i16::from(1u8)`
 
-error: casting u8 to u16 may become silently lossy if types change
+error: casting u8 to i32 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:12:5
    |
-12 |     1u8 as u16;
-   |     ^^^^^^^^^^ help: try: `u16::from(1u8)`
+LL |     1u8 as i32;
+   |     ^^^^^^^^^^ help: try: `i32::from(1u8)`
 
-error: casting u8 to u32 may become silently lossy if types change
+error: casting u8 to i64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:13:5
    |
-13 |     1u8 as u32;
-   |     ^^^^^^^^^^ help: try: `u32::from(1u8)`
+LL |     1u8 as i64;
+   |     ^^^^^^^^^^ help: try: `i64::from(1u8)`
 
-error: casting u8 to u64 may become silently lossy if types change
+error: casting u8 to u16 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:14:5
    |
-14 |     1u8 as u64;
-   |     ^^^^^^^^^^ help: try: `u64::from(1u8)`
+LL |     1u8 as u16;
+   |     ^^^^^^^^^^ help: try: `u16::from(1u8)`
 
-error: casting i16 to i32 may become silently lossy if types change
+error: casting u8 to u32 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:15:5
    |
-15 |     1i16 as i32;
-   |     ^^^^^^^^^^^ help: try: `i32::from(1i16)`
+LL |     1u8 as u32;
+   |     ^^^^^^^^^^ help: try: `u32::from(1u8)`
 
-error: casting i16 to i64 may become silently lossy if types change
+error: casting u8 to u64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:16:5
    |
-16 |     1i16 as i64;
-   |     ^^^^^^^^^^^ help: try: `i64::from(1i16)`
+LL |     1u8 as u64;
+   |     ^^^^^^^^^^ help: try: `u64::from(1u8)`
 
-error: casting u16 to i32 may become silently lossy if types change
+error: casting i16 to i32 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:17:5
    |
-17 |     1u16 as i32;
-   |     ^^^^^^^^^^^ help: try: `i32::from(1u16)`
+LL |     1i16 as i32;
+   |     ^^^^^^^^^^^ help: try: `i32::from(1i16)`
 
-error: casting u16 to i64 may become silently lossy if types change
+error: casting i16 to i64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:18:5
    |
-18 |     1u16 as i64;
-   |     ^^^^^^^^^^^ help: try: `i64::from(1u16)`
+LL |     1i16 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1i16)`
 
-error: casting u16 to u32 may become silently lossy if types change
+error: casting u16 to i32 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:19:5
    |
-19 |     1u16 as u32;
-   |     ^^^^^^^^^^^ help: try: `u32::from(1u16)`
+LL |     1u16 as i32;
+   |     ^^^^^^^^^^^ help: try: `i32::from(1u16)`
 
-error: casting u16 to u64 may become silently lossy if types change
+error: casting u16 to i64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:20:5
    |
-20 |     1u16 as u64;
-   |     ^^^^^^^^^^^ help: try: `u64::from(1u16)`
+LL |     1u16 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1u16)`
 
-error: casting i32 to i64 may become silently lossy if types change
+error: casting u16 to u32 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:21:5
    |
-21 |     1i32 as i64;
-   |     ^^^^^^^^^^^ help: try: `i64::from(1i32)`
+LL |     1u16 as u32;
+   |     ^^^^^^^^^^^ help: try: `u32::from(1u16)`
 
-error: casting u32 to i64 may become silently lossy if types change
+error: casting u16 to u64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:22:5
    |
-22 |     1u32 as i64;
-   |     ^^^^^^^^^^^ help: try: `i64::from(1u32)`
+LL |     1u16 as u64;
+   |     ^^^^^^^^^^^ help: try: `u64::from(1u16)`
 
-error: casting u32 to u64 may become silently lossy if types change
+error: casting i32 to i64 may become silently lossy if you later change the type
   --> $DIR/cast_lossless_integer.rs:23:5
    |
-23 |     1u32 as u64;
+LL |     1i32 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1i32)`
+
+error: casting u32 to i64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:24:5
+   |
+LL |     1u32 as i64;
+   |     ^^^^^^^^^^^ help: try: `i64::from(1u32)`
+
+error: casting u32 to u64 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:25:5
+   |
+LL |     1u32 as u64;
    |     ^^^^^^^^^^^ help: try: `u64::from(1u32)`
 
-error: aborting due to 18 previous errors
+error: casting u8 to u16 may become silently lossy if you later change the type
+  --> $DIR/cast_lossless_integer.rs:28:5
+   |
+LL |     (1u8 + 1u8) as u16;
+   |     ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)`
+
+error: aborting due to 19 previous errors
 
diff --git a/tests/ui/cast_ref_to_mut.rs b/tests/ui/cast_ref_to_mut.rs
new file mode 100644 (file)
index 0000000..089e5cf
--- /dev/null
@@ -0,0 +1,31 @@
+#![warn(clippy::cast_ref_to_mut)]
+#![allow(clippy::no_effect)]
+
+extern "C" {
+    // N.B., mutability can be easily incorrect in FFI calls -- as
+    // in C, the default is mutable pointers.
+    fn ffi(c: *mut u8);
+    fn int_ffi(c: *mut i32);
+}
+
+fn main() {
+    let s = String::from("Hello");
+    let a = &s;
+    unsafe {
+        let num = &3i32;
+        let mut_num = &mut 3i32;
+        // Should be warned against
+        (*(a as *const _ as *mut String)).push_str(" world");
+        *(a as *const _ as *mut _) = String::from("Replaced");
+        *(a as *const _ as *mut String) += " world";
+        // Shouldn't be warned against
+        println!("{}", *(num as *const _ as *const i16));
+        println!("{}", *(mut_num as *mut _ as *mut i16));
+        ffi(a.as_ptr() as *mut _);
+        int_ffi(num as *const _ as *mut _);
+        int_ffi(&3 as *const _ as *mut _);
+        let mut value = 3;
+        let value: *const i32 = &mut value;
+        *(value as *const i16 as *mut i16) = 42;
+    }
+}
diff --git a/tests/ui/cast_ref_to_mut.stderr b/tests/ui/cast_ref_to_mut.stderr
new file mode 100644 (file)
index 0000000..448a66c
--- /dev/null
@@ -0,0 +1,22 @@
+error: casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell
+  --> $DIR/cast_ref_to_mut.rs:18:9
+   |
+LL |         (*(a as *const _ as *mut String)).push_str(" world");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-ref-to-mut` implied by `-D warnings`
+
+error: casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell
+  --> $DIR/cast_ref_to_mut.rs:19:9
+   |
+LL |         *(a as *const _ as *mut _) = String::from("Replaced");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting &T to &mut T may cause undefined behaviour, consider instead using an UnsafeCell
+  --> $DIR/cast_ref_to_mut.rs:20:9
+   |
+LL |         *(a as *const _ as *mut String) += " world";
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index d0bef860c709ccb8d689ea1b84d9e9de42b10cbc..611e5a855723dafa0efde6cedec22bccd03d212c 100644 (file)
@@ -1,12 +1,20 @@
-#[warn(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap, cast_lossless)]
-#[allow(no_effect, unnecessary_operation)]
+#[warn(
+    clippy::cast_precision_loss,
+    clippy::cast_possible_truncation,
+    clippy::cast_sign_loss,
+    clippy::cast_possible_wrap,
+    clippy::cast_lossless
+)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
 fn main() {
     // Casting from *size
     1isize as i8;
-    1isize as f64;
-    1usize as f64;
-    1isize as f32;
-    1usize as f32;
+    let x0 = 1isize;
+    let x1 = 1usize;
+    x0 as f64;
+    x1 as f64;
+    x0 as f32;
+    x1 as f32;
     1isize as i32;
     1isize as u32;
     1usize as u32;
@@ -20,4 +28,7 @@ fn main() {
     1u32 as usize; // Should not trigger any lint
     1i32 as isize; // Neither should this
     1i32 as usize;
+    // Big integer literal to float
+    999_999_999 as f32;
+    9_999_999_999_999_999usize as f64;
 }
index 1c4b12bcebf8d0f9cf1e52ad6f6f033c4d1e9167..735e522b40d9fa25eb93628aec751c6efdfb158b 100644 (file)
 error: casting isize to i8 may truncate the value
--> $DIR/cast_size.rs:5:5
-  |
-5 |     1isize as i8;
-  |     ^^^^^^^^^^^^
-  |
-  = note: `-D cast-possible-truncation` implied by `-D warnings`
 --> $DIR/cast_size.rs:11:5
+   |
+LL |     1isize as i8;
+   |     ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cast-possible-truncation` implied by `-D warnings`
 
 error: casting isize to f64 causes a loss of precision on targets with 64-bit wide pointers (isize is 64 bits wide, but f64's mantissa is only 52 bits wide)
--> $DIR/cast_size.rs:6:5
-  |
-6 |     1isize as f64;
-  |     ^^^^^^^^^^^^^
-  |
-  = note: `-D cast-precision-loss` implied by `-D warnings`
 --> $DIR/cast_size.rs:14:5
+   |
+LL |     x0 as f64;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::cast-precision-loss` implied by `-D warnings`
 
 error: casting usize to f64 causes a loss of precision on targets with 64-bit wide pointers (usize is 64 bits wide, but f64's mantissa is only 52 bits wide)
--> $DIR/cast_size.rs:7:5
-  |
-7 |     1usize as f64;
-  |     ^^^^^^^^^^^^^
 --> $DIR/cast_size.rs:15:5
+   |
+LL |     x1 as f64;
+   |     ^^^^^^^^^
 
 error: casting isize to f32 causes a loss of precision (isize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide)
--> $DIR/cast_size.rs:8:5
-  |
-8 |     1isize as f32;
-  |     ^^^^^^^^^^^^^
 --> $DIR/cast_size.rs:16:5
+   |
+LL |     x0 as f32;
+   |     ^^^^^^^^^
 
 error: casting usize to f32 causes a loss of precision (usize is 32 or 64 bits wide, but f32's mantissa is only 23 bits wide)
- --> $DIR/cast_size.rs:9:5
-  |
-9 |     1usize as f32;
-  |     ^^^^^^^^^^^^^
-
-error: casting isize to i32 may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:10:5
+  --> $DIR/cast_size.rs:17:5
    |
-10 |     1isize as i32;
-   |     ^^^^^^^^^^^^^
+LL |     x1 as f32;
+   |     ^^^^^^^^^
 
-error: casting isize to u32 may lose the sign of the value
-  --> $DIR/cast_size.rs:11:5
+error: casting isize to i32 may truncate the value on targets with 64-bit wide pointers
+  --> $DIR/cast_size.rs:18:5
    |
-11 |     1isize as u32;
+LL |     1isize as i32;
    |     ^^^^^^^^^^^^^
-   |
-   = note: `-D cast-sign-loss` implied by `-D warnings`
 
 error: casting isize to u32 may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:11:5
+  --> $DIR/cast_size.rs:19:5
    |
-11 |     1isize as u32;
+LL |     1isize as u32;
    |     ^^^^^^^^^^^^^
 
 error: casting usize to u32 may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:12:5
+  --> $DIR/cast_size.rs:20:5
    |
-12 |     1usize as u32;
+LL |     1usize as u32;
    |     ^^^^^^^^^^^^^
 
 error: casting usize to i32 may truncate the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:13:5
+  --> $DIR/cast_size.rs:21:5
    |
-13 |     1usize as i32;
+LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting usize to i32 may wrap around the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:13:5
+  --> $DIR/cast_size.rs:21:5
    |
-13 |     1usize as i32;
+LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
    |
-   = note: `-D cast-possible-wrap` implied by `-D warnings`
+   = note: `-D clippy::cast-possible-wrap` implied by `-D warnings`
 
 error: casting i64 to isize may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:15:5
-   |
-15 |     1i64 as isize;
-   |     ^^^^^^^^^^^^^
-
-error: casting i64 to usize may lose the sign of the value
-  --> $DIR/cast_size.rs:16:5
+  --> $DIR/cast_size.rs:23:5
    |
-16 |     1i64 as usize;
+LL |     1i64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting i64 to usize may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:16:5
+  --> $DIR/cast_size.rs:24:5
    |
-16 |     1i64 as usize;
+LL |     1i64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting u64 to isize may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:17:5
+  --> $DIR/cast_size.rs:25:5
    |
-17 |     1u64 as isize;
+LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting u64 to isize may wrap around the value on targets with 64-bit wide pointers
-  --> $DIR/cast_size.rs:17:5
+  --> $DIR/cast_size.rs:25:5
    |
-17 |     1u64 as isize;
+LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting u64 to usize may truncate the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:18:5
+  --> $DIR/cast_size.rs:26:5
    |
-18 |     1u64 as usize;
+LL |     1u64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting u32 to isize may wrap around the value on targets with 32-bit wide pointers
-  --> $DIR/cast_size.rs:19:5
+  --> $DIR/cast_size.rs:27:5
    |
-19 |     1u32 as isize;
+LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
-error: casting i32 to usize may lose the sign of the value
-  --> $DIR/cast_size.rs:22:5
+error: casting i32 to f32 causes a loss of precision (i32 is 32 bits wide, but f32's mantissa is only 23 bits wide)
+  --> $DIR/cast_size.rs:32:5
    |
-22 |     1i32 as usize;
-   |     ^^^^^^^^^^^^^
+LL |     999_999_999 as f32;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: casting usize to f64 causes a loss of precision on targets with 64-bit wide pointers (usize is 64 bits wide, but f64's mantissa is only 52 bits wide)
+  --> $DIR/cast_size.rs:33:5
+   |
+LL |     9_999_999_999_999_999usize as f64;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 19 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/tests/ui/cfg_attr_rustfmt.fixed b/tests/ui/cfg_attr_rustfmt.fixed
new file mode 100644 (file)
index 0000000..4e583a2
--- /dev/null
@@ -0,0 +1,31 @@
+// run-rustfix
+#![feature(stmt_expr_attributes)]
+
+#![allow(unused, clippy::no_effect)]
+#![warn(clippy::deprecated_cfg_attr)]
+
+// This doesn't get linted, see known problems
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+#[rustfmt::skip]
+trait Foo
+{
+fn foo(
+);
+}
+
+fn skip_on_statements() {
+    #[rustfmt::skip]
+    5+3;
+}
+
+#[rustfmt::skip]
+fn main() {
+    foo::f();
+}
+
+mod foo {
+    #![cfg_attr(rustfmt, rustfmt_skip)]
+
+    pub fn f() {}
+}
diff --git a/tests/ui/cfg_attr_rustfmt.rs b/tests/ui/cfg_attr_rustfmt.rs
new file mode 100644 (file)
index 0000000..9c0fcf6
--- /dev/null
@@ -0,0 +1,31 @@
+// run-rustfix
+#![feature(stmt_expr_attributes)]
+
+#![allow(unused, clippy::no_effect)]
+#![warn(clippy::deprecated_cfg_attr)]
+
+// This doesn't get linted, see known problems
+#![cfg_attr(rustfmt, rustfmt_skip)]
+
+#[rustfmt::skip]
+trait Foo
+{
+fn foo(
+);
+}
+
+fn skip_on_statements() {
+    #[cfg_attr(rustfmt, rustfmt::skip)]
+    5+3;
+}
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn main() {
+    foo::f();
+}
+
+mod foo {
+    #![cfg_attr(rustfmt, rustfmt_skip)]
+
+    pub fn f() {}
+}
diff --git a/tests/ui/cfg_attr_rustfmt.stderr b/tests/ui/cfg_attr_rustfmt.stderr
new file mode 100644 (file)
index 0000000..09971ca
--- /dev/null
@@ -0,0 +1,16 @@
+error: `cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes
+  --> $DIR/cfg_attr_rustfmt.rs:18:5
+   |
+LL |     #[cfg_attr(rustfmt, rustfmt::skip)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
+   |
+   = note: `-D clippy::deprecated-cfg-attr` implied by `-D warnings`
+
+error: `cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes
+  --> $DIR/cfg_attr_rustfmt.rs:22:1
+   |
+LL | #[cfg_attr(rustfmt, rustfmt_skip)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
+
+error: aborting due to 2 previous errors
+
index c69181c7649327aa270d55a23fc36c5eb2f7f69b..211cbfe98f3d421badb441aaaceee6dde713baf9 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![warn(char_lit_as_u8)]
+#![warn(clippy::char_lit_as_u8)]
 #![allow(unused_variables)]
 fn main() {
     let c = 'a' as u8;
index fcf038fe002db9d32e7fb59641416203cdb210f2..52f29a3f553cf48f8404c0785048f682ef89cbcd 100644 (file)
@@ -1,12 +1,12 @@
 error: casting character literal to u8. `char`s are 4 bytes wide in rust, so casting to u8 truncates them
--> $DIR/char_lit_as_u8.rs:7:13
-  |
-7 |     let c = 'a' as u8;
-  |             ^^^^^^^^^
-  |
-  = note: `-D char-lit-as-u8` implied by `-D warnings`
-  = help: Consider using a byte literal instead:
-          b'a'
 --> $DIR/char_lit_as_u8.rs:4:13
+   |
+LL |     let c = 'a' as u8;
+   |             ^^^^^^^^^
+   |
+   = note: `-D clippy::char-lit-as-u8` implied by `-D warnings`
+   = help: Consider using a byte literal instead:
+           b'a'
 
 error: aborting due to previous error
 
index 2b5118fa814e48aa162be706bb9bf2b4f25bbdb4..21f9e33201f1127709c58e1f31488bef6d30f56a 100644 (file)
@@ -1,5 +1,5 @@
-#![deny(panicking_unwrap, unnecessary_unwrap)]
-#![allow(if_same_then_else)]
+#![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+#![allow(clippy::if_same_then_else)]
 
 fn main() {
     let x = Some(());
@@ -31,11 +31,11 @@ fn main() {
     if x.is_ok() {
         x = Err(());
         x.unwrap(); // not unnecessary because of mutation of x
-        // it will always panic but the lint is not smart enough to see this (it only checks if conditions).
+                    // it will always panic but the lint is not smart enough to see this (it only checks if conditions).
     } else {
         x = Ok(());
         x.unwrap_err(); // not unnecessary because of mutation of x
-        // it will always panic but the lint is not smart enough to see this (it only checks if conditions).
+                        // it will always panic but the lint is not smart enough to see this (it only checks if conditions).
     }
 }
 
index 1b46ceb5fa8d145ad6533c51a3da1ad104c4518c..514814b0ee022233b1a845f8b176f21e9ac5d24f 100644 (file)
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
- --> $DIR/checked_unwrap.rs:7:9
-  |
-6 |     if x.is_some() {
-  |        ----------- the check is happening here
-7 |         x.unwrap(); // unnecessary
-  |         ^^^^^^^^^^
-  |
 --> $DIR/checked_unwrap.rs:7:9
+   |
+LL |     if x.is_some() {
+   |        ----------- the check is happening here
+LL |         x.unwrap(); // unnecessary
+   |         ^^^^^^^^^^
+   |
 note: lint level defined here
- --> $DIR/checked_unwrap.rs:1:27
-  |
-1 | #![deny(panicking_unwrap, unnecessary_unwrap)]
-  |                           ^^^^^^^^^^^^^^^^^^
+  --> $DIR/checked_unwrap.rs:1:35
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
- --> $DIR/checked_unwrap.rs:9:9
-  |
-6 |     if x.is_some() {
-  |        ----------- because of this check
 --> $DIR/checked_unwrap.rs:9:9
+   |
+LL |     if x.is_some() {
+   |        ----------- because of this check
 ...
-9 |         x.unwrap(); // will panic
-  |         ^^^^^^^^^^
-  |
+LL |         x.unwrap(); // will panic
+   |         ^^^^^^^^^^
+   |
 note: lint level defined here
- --> $DIR/checked_unwrap.rs:1:9
-  |
-1 | #![deny(panicking_unwrap, unnecessary_unwrap)]
-  |         ^^^^^^^^^^^^^^^^
 --> $DIR/checked_unwrap.rs:1:9
+   |
+LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:12:9
    |
-11 |     if x.is_none() {
+LL |     if x.is_none() {
    |        ----------- because of this check
-12 |         x.unwrap(); // will panic
+LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:14:9
    |
-11 |     if x.is_none() {
+LL |     if x.is_none() {
    |        ----------- the check is happening here
 ...
-14 |         x.unwrap(); // unnecessary
+LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:18:9
    |
-17 |     if x.is_ok() {
+LL |     if x.is_ok() {
    |        --------- the check is happening here
-18 |         x.unwrap(); // unnecessary
+LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
   --> $DIR/checked_unwrap.rs:19:9
    |
-17 |     if x.is_ok() {
+LL |     if x.is_ok() {
    |        --------- because of this check
-18 |         x.unwrap(); // unnecessary
-19 |         x.unwrap_err(); // will panic
+LL |         x.unwrap(); // unnecessary
+LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:21:9
    |
-17 |     if x.is_ok() {
+LL |     if x.is_ok() {
    |        --------- because of this check
 ...
-21 |         x.unwrap(); // will panic
+LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:22:9
    |
-17 |     if x.is_ok() {
+LL |     if x.is_ok() {
    |        --------- the check is happening here
 ...
-22 |         x.unwrap_err(); // unnecessary
+LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:25:9
    |
-24 |     if x.is_err() {
+LL |     if x.is_err() {
    |        ---------- because of this check
-25 |         x.unwrap(); // will panic
+LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:26:9
    |
-24 |     if x.is_err() {
+LL |     if x.is_err() {
    |        ---------- the check is happening here
-25 |         x.unwrap(); // will panic
-26 |         x.unwrap_err(); // unnecessary
+LL |         x.unwrap(); // will panic
+LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:28:9
    |
-24 |     if x.is_err() {
+LL |     if x.is_err() {
    |        ---------- the check is happening here
 ...
-28 |         x.unwrap(); // unnecessary
+LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
   --> $DIR/checked_unwrap.rs:29:9
    |
-24 |     if x.is_err() {
+LL |     if x.is_err() {
    |        ---------- because of this check
 ...
-29 |         x.unwrap_err(); // will panic
+LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:46:9
    |
-45 |     if x.is_ok() && y.is_err() {
+LL |     if x.is_ok() && y.is_err() {
    |        --------- the check is happening here
-46 |         x.unwrap(); // unnecessary
+LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
   --> $DIR/checked_unwrap.rs:47:9
    |
-45 |     if x.is_ok() && y.is_err() {
+LL |     if x.is_ok() && y.is_err() {
    |        --------- because of this check
-46 |         x.unwrap(); // unnecessary
-47 |         x.unwrap_err(); // will panic
+LL |         x.unwrap(); // unnecessary
+LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:48:9
    |
-45 |     if x.is_ok() && y.is_err() {
+LL |     if x.is_ok() && y.is_err() {
    |                     ---------- because of this check
 ...
-48 |         y.unwrap(); // will panic
+LL |         y.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:49:9
    |
-45 |     if x.is_ok() && y.is_err() {
+LL |     if x.is_ok() && y.is_err() {
    |                     ---------- the check is happening here
 ...
-49 |         y.unwrap_err(); // unnecessary
+LL |         y.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:63:9
    |
-58 |     if x.is_ok() || y.is_ok() {
+LL |     if x.is_ok() || y.is_ok() {
    |        --------- because of this check
 ...
-63 |         x.unwrap(); // will panic
+LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:64:9
    |
-58 |     if x.is_ok() || y.is_ok() {
+LL |     if x.is_ok() || y.is_ok() {
    |        --------- the check is happening here
 ...
-64 |         x.unwrap_err(); // unnecessary
+LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:65:9
    |
-58 |     if x.is_ok() || y.is_ok() {
+LL |     if x.is_ok() || y.is_ok() {
    |                     --------- because of this check
 ...
-65 |         y.unwrap(); // will panic
+LL |         y.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:66:9
    |
-58 |     if x.is_ok() || y.is_ok() {
+LL |     if x.is_ok() || y.is_ok() {
    |                     --------- the check is happening here
 ...
-66 |         y.unwrap_err(); // unnecessary
+LL |         y.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:70:9
    |
-69 |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
    |        --------- the check is happening here
-70 |         x.unwrap(); // unnecessary
+LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
   --> $DIR/checked_unwrap.rs:71:9
    |
-69 |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
    |        --------- because of this check
-70 |         x.unwrap(); // unnecessary
-71 |         x.unwrap_err(); // will panic
+LL |         x.unwrap(); // unnecessary
+LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:72:9
    |
-69 |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
    |                       --------- because of this check
 ...
-72 |         y.unwrap(); // will panic
+LL |         y.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:73:9
    |
-69 |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
    |                       --------- the check is happening here
 ...
-73 |         y.unwrap_err(); // unnecessary
+LL |         y.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:74:9
    |
-69 |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
    |                                    ---------- the check is happening here
 ...
-74 |         z.unwrap(); // unnecessary
+LL |         z.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
   --> $DIR/checked_unwrap.rs:75:9
    |
-69 |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
+LL |     if x.is_ok() && !(y.is_ok() || z.is_err()) {
    |                                    ---------- because of this check
 ...
-75 |         z.unwrap_err(); // will panic
+LL |         z.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:83:9
    |
-77 |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
    |        --------- because of this check
 ...
-83 |         x.unwrap(); // will panic
+LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:84:9
    |
-77 |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
    |        --------- the check is happening here
 ...
-84 |         x.unwrap_err(); // unnecessary
+LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:85:9
    |
-77 |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
    |                       --------- the check is happening here
 ...
-85 |         y.unwrap(); // unnecessary
+LL |         y.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
   --> $DIR/checked_unwrap.rs:86:9
    |
-77 |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
    |                       --------- because of this check
 ...
-86 |         y.unwrap_err(); // will panic
+LL |         y.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:87:9
    |
-77 |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
    |                                    ---------- because of this check
 ...
-87 |         z.unwrap(); // will panic
+LL |         z.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:88:9
    |
-77 |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
+LL |     if x.is_ok() || !(y.is_ok() && z.is_err()) {
    |                                    ---------- the check is happening here
 ...
-88 |         z.unwrap_err(); // unnecessary
+LL |         z.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
   --> $DIR/checked_unwrap.rs:96:13
    |
-95 |         if x.is_some() {
+LL |         if x.is_some() {
    |            ----------- the check is happening here
-96 |             x.unwrap(); // unnecessary
+LL |             x.unwrap(); // unnecessary
    |             ^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
   --> $DIR/checked_unwrap.rs:98:13
    |
-95 |         if x.is_some() {
+LL |         if x.is_some() {
    |            ----------- because of this check
 ...
-98 |             x.unwrap(); // will panic
+LL |             x.unwrap(); // will panic
    |             ^^^^^^^^^^
 
 error: aborting due to 34 previous errors
index e21441640f34a1c34b0b64cc1b317dc85f823be4..8f9f2a0db8c437df5e8eaa9dc41315fdfcf2510d 100644 (file)
@@ -1,5 +1,5 @@
-use std::marker::PhantomData;
 use std::fmt;
+use std::marker::PhantomData;
 
 pub struct Key<T> {
     #[doc(hidden)]
index 5b491573c3f9202f0939e6d0d57d4d703432f925..3cbbcb7c08305c7f1b0d00a47abfbd7137f45283 100644 (file)
@@ -5,7 +5,7 @@ pub fn dec_read_dec(i: &mut i32) -> i32 {
     ret
 }
 
-#[allow(trivially_copy_pass_by_ref)]
+#[allow(clippy::trivially_copy_pass_by_ref)]
 pub fn minus_1(i: &i32) -> i32 {
     dec_read_dec(&mut i.clone())
 }
index 71dfdd43da7cc0c745ff1a625d8f10762f0cbd6b..33e039308ece0c7c1f21b77baf6250067eff92dd 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#[warn(cmp_nan)]
-#[allow(float_cmp, no_effect, unnecessary_operation)]
+#[warn(clippy::cmp_nan)]
+#[allow(clippy::float_cmp, clippy::no_effect, clippy::unnecessary_operation)]
 fn main() {
     let x = 5f32;
     x == std::f32::NAN;
index 46f3d3d57e0c7fbd8429091b872a5312bc2d5dc9..421f3451823d3aa8be772a96a6b092ef0f41fb10 100644 (file)
@@ -1,75 +1,75 @@
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
--> $DIR/cmp_nan.rs:8:5
-  |
-8 |     x == std::f32::NAN;
-  |     ^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D cmp-nan` implied by `-D warnings`
 --> $DIR/cmp_nan.rs:5:5
+   |
+LL |     x == std::f32::NAN;
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cmp-nan` implied by `-D warnings`
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
--> $DIR/cmp_nan.rs:9:5
-  |
-9 |     x != std::f32::NAN;
-  |     ^^^^^^^^^^^^^^^^^^
 --> $DIR/cmp_nan.rs:6:5
+   |
+LL |     x != std::f32::NAN;
+   |     ^^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:10:5
+  --> $DIR/cmp_nan.rs:7:5
    |
-10 |     x < std::f32::NAN;
+LL |     x < std::f32::NAN;
    |     ^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:11:5
+  --> $DIR/cmp_nan.rs:8:5
    |
-11 |     x > std::f32::NAN;
+LL |     x > std::f32::NAN;
    |     ^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:12:5
+  --> $DIR/cmp_nan.rs:9:5
    |
-12 |     x <= std::f32::NAN;
+LL |     x <= std::f32::NAN;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:13:5
+  --> $DIR/cmp_nan.rs:10:5
    |
-13 |     x >= std::f32::NAN;
+LL |     x >= std::f32::NAN;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:16:5
+  --> $DIR/cmp_nan.rs:13:5
    |
-16 |     y == std::f64::NAN;
+LL |     y == std::f64::NAN;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:17:5
+  --> $DIR/cmp_nan.rs:14:5
    |
-17 |     y != std::f64::NAN;
+LL |     y != std::f64::NAN;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:18:5
+  --> $DIR/cmp_nan.rs:15:5
    |
-18 |     y < std::f64::NAN;
+LL |     y < std::f64::NAN;
    |     ^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:19:5
+  --> $DIR/cmp_nan.rs:16:5
    |
-19 |     y > std::f64::NAN;
+LL |     y > std::f64::NAN;
    |     ^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:20:5
+  --> $DIR/cmp_nan.rs:17:5
    |
-20 |     y <= std::f64::NAN;
+LL |     y <= std::f64::NAN;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead
-  --> $DIR/cmp_nan.rs:21:5
+  --> $DIR/cmp_nan.rs:18:5
    |
-21 |     y >= std::f64::NAN;
+LL |     y >= std::f64::NAN;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 12 previous errors
index 0f463bcfc30df74bcb051c56a7035699bec1e996..2d2d04178c35d21bc04ed1d1526c9a4378563fde 100644 (file)
@@ -1,18 +1,16 @@
-
-
-#![warn(cmp_null)]
+#![warn(clippy::cmp_null)]
 #![allow(unused_mut)]
 
 use std::ptr;
 
 fn main() {
     let x = 0;
-    let p : *const usize = &x;
+    let p: *const usize = &x;
     if p == ptr::null() {
         println!("This is surprising!");
     }
     let mut y = 0;
-    let mut m : *mut usize = &mut y;
+    let mut m: *mut usize = &mut y;
     if m == ptr::null_mut() {
         println!("This is surprising, too!");
     }
index 481a4d0f9420586a868c16b7077cd2d6bbf1fa7f..063e716676ce49ffe85c9b5f3f8600b413f14ee9 100644 (file)
@@ -1,15 +1,15 @@
 error: Comparing with null is better expressed by the .is_null() method
-  --> $DIR/cmp_null.rs:11:8
+  --> $DIR/cmp_null.rs:9:8
    |
-11 |     if p == ptr::null() {
+LL |     if p == ptr::null() {
    |        ^^^^^^^^^^^^^^^^
    |
-   = note: `-D cmp-null` implied by `-D warnings`
+   = note: `-D clippy::cmp-null` implied by `-D warnings`
 
 error: Comparing with null is better expressed by the .is_null() method
-  --> $DIR/cmp_null.rs:16:8
+  --> $DIR/cmp_null.rs:14:8
    |
-16 |     if m == ptr::null_mut() {
+LL |     if m == ptr::null_mut() {
    |        ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
index 36d3140d246fb30697ccef5b49d551fa140edefc..a5f92b30bc2ba7de63a8eb041c3f3475ff184c68 100644 (file)
@@ -1,10 +1,7 @@
-
-
-
-#[warn(cmp_owned)]
-#[allow(unnecessary_operation)]
+#[warn(clippy::cmp_owned)]
+#[allow(clippy::unnecessary_operation)]
 fn main() {
-    fn with_to_string(x : &str) {
+    fn with_to_string(x: &str) {
         x != "foo".to_string();
 
         "foo".to_string() != x;
@@ -21,6 +18,20 @@ fn with_to_string(x : &str) {
     42.to_string() == "42";
 
     Foo.to_owned() == Foo;
+
+    "abc".chars().filter(|c| c.to_owned() != 'X');
+
+    "abc".chars().filter(|c| *c != 'X');
+
+    let x = &Baz;
+    let y = &Baz;
+
+    y.to_owned() == *x;
+
+    let x = &&Baz;
+    let y = &Baz;
+
+    y.to_owned() == **x;
 }
 
 struct Foo;
@@ -53,3 +64,13 @@ fn borrow(&self) -> &Foo {
         &FOO
     }
 }
+
+#[derive(PartialEq)]
+struct Baz;
+
+impl ToOwned for Baz {
+    type Owned = Baz;
+    fn to_owned(&self) -> Baz {
+        Baz
+    }
+}
index d40fb4b8add877faa25126d3efe775dcc435e751..9be749f8d04046f4ff89aeeec70e2bb1e0b023c8 100644 (file)
@@ -1,40 +1,58 @@
 error: this creates an owned instance just for comparison
--> $DIR/cmp_owned.rs:8:14
-  |
-8 |         x != "foo".to_string();
-  |              ^^^^^^^^^^^^^^^^^ help: try: `"foo"`
-  |
-  = note: `-D cmp-owned` implied by `-D warnings`
 --> $DIR/cmp_owned.rs:5:14
+   |
+LL |         x != "foo".to_string();
+   |              ^^^^^^^^^^^^^^^^^ help: try: `"foo"`
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
 
 error: this creates an owned instance just for comparison
-  --> $DIR/cmp_owned.rs:10:9
+  --> $DIR/cmp_owned.rs:7:9
    |
-10 |         "foo".to_string() != x;
+LL |         "foo".to_string() != x;
    |         ^^^^^^^^^^^^^^^^^ help: try: `"foo"`
 
 error: this creates an owned instance just for comparison
-  --> $DIR/cmp_owned.rs:17:10
+  --> $DIR/cmp_owned.rs:14:10
    |
-17 |     x != "foo".to_owned();
+LL |     x != "foo".to_owned();
    |          ^^^^^^^^^^^^^^^^ help: try: `"foo"`
 
 error: this creates an owned instance just for comparison
-  --> $DIR/cmp_owned.rs:19:10
+  --> $DIR/cmp_owned.rs:16:10
    |
-19 |     x != String::from("foo");
+LL |     x != String::from("foo");
    |          ^^^^^^^^^^^^^^^^^^^ help: try: `"foo"`
 
 error: this creates an owned instance just for comparison
-  --> $DIR/cmp_owned.rs:23:5
+  --> $DIR/cmp_owned.rs:20:5
    |
-23 |     Foo.to_owned() == Foo;
+LL |     Foo.to_owned() == Foo;
    |     ^^^^^^^^^^^^^^ help: try: `Foo`
 
 error: this creates an owned instance just for comparison
-  --> $DIR/cmp_owned.rs:30:9
+  --> $DIR/cmp_owned.rs:22:30
+   |
+LL |     "abc".chars().filter(|c| c.to_owned() != 'X');
+   |                              ^^^^^^^^^^^^ help: try: `*c`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/cmp_owned.rs:29:5
+   |
+LL |     y.to_owned() == *x;
+   |     ^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
+
+error: this creates an owned instance just for comparison
+  --> $DIR/cmp_owned.rs:34:5
+   |
+LL |     y.to_owned() == **x;
+   |     ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
+
+error: this creates an owned instance just for comparison
+  --> $DIR/cmp_owned.rs:41:9
    |
-30 |         self.to_owned() == *other
-   |         ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating
+LL |         self.to_owned() == *other
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating
 
-error: aborting due to 6 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/cognitive_complexity.rs b/tests/ui/cognitive_complexity.rs
new file mode 100644 (file)
index 0000000..4e4016e
--- /dev/null
@@ -0,0 +1,371 @@
+#![allow(clippy::all)]
+#![warn(clippy::cognitive_complexity)]
+#![allow(unused)]
+
+#[rustfmt::skip]
+fn main() {
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+    if true {
+        println!("a");
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn kaboom() {
+    let n = 0;
+    'a: for i in 0..20 {
+        'b: for j in i..20 {
+            for k in j..20 {
+                if k == 5 {
+                    break 'b;
+                }
+                if j == 3 && k == 6 {
+                    continue 'a;
+                }
+                if k == j {
+                    continue;
+                }
+                println!("bake");
+            }
+        }
+        println!("cake");
+    }
+}
+
+fn bloo() {
+    match 42 {
+        0 => println!("hi"),
+        1 => println!("hai"),
+        2 => println!("hey"),
+        3 => println!("hallo"),
+        4 => println!("hello"),
+        5 => println!("salut"),
+        6 => println!("good morning"),
+        7 => println!("good evening"),
+        8 => println!("good afternoon"),
+        9 => println!("good night"),
+        10 => println!("bonjour"),
+        11 => println!("hej"),
+        12 => println!("hej hej"),
+        13 => println!("greetings earthling"),
+        14 => println!("take us to you leader"),
+        15 | 17 | 19 | 21 | 23 | 25 | 27 | 29 | 31 | 33 => println!("take us to you leader"),
+        35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | 53 => println!("there is no undefined behavior"),
+        55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 73 => println!("I know borrow-fu"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn lots_of_short_circuits() -> bool {
+    true && false && true && false && true && false && true
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn lots_of_short_circuits2() -> bool {
+    true || false || true || false || true || false || true
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn baa() {
+    let x = || match 99 {
+        0 => 0,
+        1 => 1,
+        2 => 2,
+        4 => 4,
+        6 => 6,
+        9 => 9,
+        _ => 42,
+    };
+    if x() == 42 {
+        println!("x");
+    } else {
+        println!("not x");
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn bar() {
+    match 99 {
+        0 => println!("hi"),
+        _ => println!("bye"),
+    }
+}
+
+#[test]
+#[clippy::cognitive_complexity = "0"]
+/// Tests are usually complex but simple at the same time. `clippy::cognitive_complexity` used to
+/// give lots of false-positives in tests.
+fn dont_warn_on_tests() {
+    match 99 {
+        0 => println!("hi"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn barr() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn barr2() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn barrr() {
+    match 99 {
+        0 => println!("hi"),
+        1 => panic!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn barrr2() {
+    match 99 {
+        0 => println!("hi"),
+        1 => panic!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+    match 99 {
+        0 => println!("hi"),
+        1 => panic!("bla"),
+        2 | 3 => println!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn barrrr() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => panic!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn barrrr2() {
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => panic!("blub"),
+        _ => println!("bye"),
+    }
+    match 99 {
+        0 => println!("hi"),
+        1 => println!("bla"),
+        2 | 3 => panic!("blub"),
+        _ => println!("bye"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn cake() {
+    if 4 == 5 {
+        println!("yea");
+    } else {
+        panic!("meh");
+    }
+    println!("whee");
+}
+
+#[clippy::cognitive_complexity = "0"]
+pub fn read_file(input_path: &str) -> String {
+    use std::fs::File;
+    use std::io::{Read, Write};
+    use std::path::Path;
+    let mut file = match File::open(&Path::new(input_path)) {
+        Ok(f) => f,
+        Err(err) => {
+            panic!("Can't open {}: {}", input_path, err);
+        },
+    };
+
+    let mut bytes = Vec::new();
+
+    match file.read_to_end(&mut bytes) {
+        Ok(..) => {},
+        Err(_) => {
+            panic!("Can't read {}", input_path);
+        },
+    };
+
+    match String::from_utf8(bytes) {
+        Ok(contents) => contents,
+        Err(_) => {
+            panic!("{} is not UTF-8 encoded", input_path);
+        },
+    }
+}
+
+enum Void {}
+
+#[clippy::cognitive_complexity = "0"]
+fn void(void: Void) {
+    if true {
+        match void {}
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn mcarton_sees_all() {
+    panic!("meh");
+    panic!("möh");
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn try() -> Result<i32, &'static str> {
+    match 5 {
+        5 => Ok(5),
+        _ => return Err("bla"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn try_again() -> Result<i32, &'static str> {
+    let _ = try!(Ok(42));
+    let _ = try!(Ok(43));
+    let _ = try!(Ok(44));
+    let _ = try!(Ok(45));
+    let _ = try!(Ok(46));
+    let _ = try!(Ok(47));
+    let _ = try!(Ok(48));
+    let _ = try!(Ok(49));
+    match 5 {
+        5 => Ok(5),
+        _ => return Err("bla"),
+    }
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn early() -> Result<i32, &'static str> {
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+    return Ok(5);
+}
+
+#[rustfmt::skip]
+#[clippy::cognitive_complexity = "0"]
+fn early_ret() -> i32 {
+    let a = if true { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    let a = if a < 99 { 42 } else { return 0; };
+    match 5 {
+        5 => 5,
+        _ => return 6,
+    }
+}
diff --git a/tests/ui/cognitive_complexity.stderr b/tests/ui/cognitive_complexity.stderr
new file mode 100644 (file)
index 0000000..168653b
--- /dev/null
@@ -0,0 +1,272 @@
+error: the function has a cognitive complexity of 28
+  --> $DIR/cognitive_complexity.rs:6:1
+   |
+LL | / fn main() {
+LL | |     if true {
+LL | |         println!("a");
+LL | |     }
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 7
+  --> $DIR/cognitive_complexity.rs:91:1
+   |
+LL | / fn kaboom() {
+LL | |     let n = 0;
+LL | |     'a: for i in 0..20 {
+LL | |         'b: for j in i..20 {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 1
+  --> $DIR/cognitive_complexity.rs:137:1
+   |
+LL | / fn lots_of_short_circuits() -> bool {
+LL | |     true && false && true && false && true && false && true
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 1
+  --> $DIR/cognitive_complexity.rs:142:1
+   |
+LL | / fn lots_of_short_circuits2() -> bool {
+LL | |     true || false || true || false || true || false || true
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:147:1
+   |
+LL | / fn baa() {
+LL | |     let x = || match 99 {
+LL | |         0 => 0,
+LL | |         1 => 1,
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:148:13
+   |
+LL |       let x = || match 99 {
+   |  _____________^
+LL | |         0 => 0,
+LL | |         1 => 1,
+LL | |         2 => 2,
+...  |
+LL | |         _ => 42,
+LL | |     };
+   | |_____^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:165:1
+   |
+LL | / fn bar() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         _ => println!("bye"),
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:184:1
+   |
+LL | / fn barr() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         1 => println!("bla"),
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 3
+  --> $DIR/cognitive_complexity.rs:194:1
+   |
+LL | / fn barr2() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         1 => println!("bla"),
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:210:1
+   |
+LL | / fn barrr() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         1 => panic!("bla"),
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 3
+  --> $DIR/cognitive_complexity.rs:220:1
+   |
+LL | / fn barrr2() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         1 => panic!("bla"),
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:236:1
+   |
+LL | / fn barrrr() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         1 => println!("bla"),
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 3
+  --> $DIR/cognitive_complexity.rs:246:1
+   |
+LL | / fn barrrr2() {
+LL | |     match 99 {
+LL | |         0 => println!("hi"),
+LL | |         1 => println!("bla"),
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 2
+  --> $DIR/cognitive_complexity.rs:262:1
+   |
+LL | / fn cake() {
+LL | |     if 4 == 5 {
+LL | |         println!("yea");
+LL | |     } else {
+...  |
+LL | |     println!("whee");
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 4
+  --> $DIR/cognitive_complexity.rs:272:1
+   |
+LL | / pub fn read_file(input_path: &str) -> String {
+LL | |     use std::fs::File;
+LL | |     use std::io::{Read, Write};
+LL | |     use std::path::Path;
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 1
+  --> $DIR/cognitive_complexity.rs:303:1
+   |
+LL | / fn void(void: Void) {
+LL | |     if true {
+LL | |         match void {}
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 1
+  --> $DIR/cognitive_complexity.rs:316:1
+   |
+LL | / fn try() -> Result<i32, &'static str> {
+LL | |     match 5 {
+LL | |         5 => Ok(5),
+LL | |         _ => return Err("bla"),
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 1
+  --> $DIR/cognitive_complexity.rs:324:1
+   |
+LL | / fn try_again() -> Result<i32, &'static str> {
+LL | |     let _ = try!(Ok(42));
+LL | |     let _ = try!(Ok(43));
+LL | |     let _ = try!(Ok(44));
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 1
+  --> $DIR/cognitive_complexity.rs:340:1
+   |
+LL | / fn early() -> Result<i32, &'static str> {
+LL | |     return Ok(5);
+LL | |     return Ok(5);
+LL | |     return Ok(5);
+...  |
+LL | |     return Ok(5);
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of 8
+  --> $DIR/cognitive_complexity.rs:354:1
+   |
+LL | / fn early_ret() -> i32 {
+LL | |     let a = if true { 42 } else { return 0; };
+LL | |     let a = if a < 99 { 42 } else { return 0; };
+LL | |     let a = if a < 99 { 42 } else { return 0; };
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = help: you could split it up into multiple smaller functions
+
+error: aborting due to 20 previous errors
+
diff --git a/tests/ui/cognitive_complexity_attr_used.rs b/tests/ui/cognitive_complexity_attr_used.rs
new file mode 100644 (file)
index 0000000..403eff5
--- /dev/null
@@ -0,0 +1,15 @@
+#![warn(clippy::cognitive_complexity)]
+#![warn(unused)]
+
+fn main() {
+    kaboom();
+}
+
+#[clippy::cognitive_complexity = "0"]
+fn kaboom() {
+    if 42 == 43 {
+        panic!();
+    } else if "cake" == "lie" {
+        println!("what?");
+    }
+}
diff --git a/tests/ui/cognitive_complexity_attr_used.stderr b/tests/ui/cognitive_complexity_attr_used.stderr
new file mode 100644 (file)
index 0000000..2cf4150
--- /dev/null
@@ -0,0 +1,17 @@
+error: the function has a cognitive complexity of 3
+  --> $DIR/cognitive_complexity_attr_used.rs:9:1
+   |
+LL | / fn kaboom() {
+LL | |     if 42 == 43 {
+LL | |         panic!();
+LL | |     } else if "cake" == "lie" {
+LL | |         println!("what?");
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+   = help: you could split it up into multiple smaller functions
+
+error: aborting due to previous error
+
diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed
new file mode 100644 (file)
index 0000000..69570c5
--- /dev/null
@@ -0,0 +1,175 @@
+// run-rustfix
+#![allow(clippy::cognitive_complexity, clippy::assertions_on_constants)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+    let x = "hello";
+    let y = "world";
+    if x == "hello" && y == "world" {
+    println!("Hello world!");
+}
+
+    if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
+    println!("Hello world!");
+}
+
+    if x == "hello" && x == "world" && (y == "world" || y == "hello") {
+    println!("Hello world!");
+}
+
+    if (x == "hello" || x == "world") && y == "world" && y == "hello" {
+    println!("Hello world!");
+}
+
+    if x == "hello" && x == "world" && y == "world" && y == "hello" {
+    println!("Hello world!");
+}
+
+    if 42 == 1337 && 'a' != 'A' {
+    println!("world!")
+}
+
+    // Collapse `else { if .. }` to `else if ..`
+    if x == "hello" {
+        print!("Hello ");
+    } else if y == "world" {
+    println!("world!")
+}
+
+    if x == "hello" {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+    println!("world!")
+}
+
+    if x == "hello" {
+        print!("Hello ");
+    } else if y == "world" {
+    println!("world")
+}
+else {
+    println!("!")
+}
+
+    if x == "hello" {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+    println!("world")
+}
+else {
+    println!("!")
+}
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+    println!("world")
+}
+else {
+    println!("!")
+}
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else if x == "hello" {
+    println!("world")
+}
+else {
+    println!("!")
+}
+
+    if let Some(42) = Some(42) {
+        print!("Hello ");
+    } else if let Some(42) = Some(42) {
+    println!("world")
+}
+else {
+    println!("!")
+}
+
+    // Works because any if with an else statement cannot be collapsed.
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        }
+    } else {
+        println!("Not Hello world");
+    }
+
+    if x == "hello" {
+        if y == "world" {
+            println!("Hello world!");
+        } else {
+            println!("Hello something else");
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if true {
+    } else {
+        assert!(true); // assert! is just an `if`
+    }
+
+
+    // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
+    if x == "hello" {// Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" && y == "world" { // Collapsible
+    println!("Hello world!");
+}
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if let Some(42) = Some(42) {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+}
index de22352e311ec45825a71ff7c59e27c008adf150..5dac42a3dd976aaf500ca991ccbed612a79a4c2e 100644 (file)
@@ -1,7 +1,8 @@
+// run-rustfix
+#![allow(clippy::cognitive_complexity, clippy::assertions_on_constants)]
 
-
-
-#[warn(collapsible_if)]
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
 fn main() {
     let x = "hello";
     let y = "world";
@@ -141,4 +142,62 @@ fn main() {
     } else {
         assert!(true); // assert! is just an `if`
     }
+
+
+    // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
+    if x == "hello" {// Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        // Not collapsible
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        if y == "world" { // Collapsible
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if y == "world" {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        print!("Hello ");
+    } else {
+        // Not collapsible
+        if let Some(42) = Some(42) {
+            println!("world!")
+        }
+    }
+
+    if x == "hello" {
+        /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
+
+    if x == "hello" { /* Not collapsible */
+        if y == "world" {
+            println!("Hello world!");
+        }
+    }
 }
index 69f2013c1dc847f05293ff40369d97ffc1ca3310..d6d0b9d5d4eaa276de835167837ef68718173354 100644 (file)
 error: this if statement can be collapsed
-  --> $DIR/collapsible_if.rs:8:5
+  --> $DIR/collapsible_if.rs:9:5
    |
- | /     if x == "hello" {
- | |         if y == "world" {
-10 | |             println!("Hello world!");
-11 | |         }
-12 | |     }
+LL | /     if x == "hello" {
+LL | |         if y == "world" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
    | |_____^
    |
-   = note: `-D collapsible-if` implied by `-D warnings`
+   = note: `-D clippy::collapsible-if` implied by `-D warnings`
 help: try
    |
- |     if x == "hello" && y == "world" {
- |     println!("Hello world!");
-10 | }
+LL |     if x == "hello" && y == "world" {
+LL |     println!("Hello world!");
+LL | }
    |
 
 error: this if statement can be collapsed
-  --> $DIR/collapsible_if.rs:14:5
+  --> $DIR/collapsible_if.rs:15:5
    |
-14 | /     if x == "hello" || x == "world" {
-15 | |         if y == "world" || y == "hello" {
-16 | |             println!("Hello world!");
-17 | |         }
-18 | |     }
+LL | /     if x == "hello" || x == "world" {
+LL | |         if y == "world" || y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-14 |     if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
-15 |     println!("Hello world!");
-16 | }
+LL |     if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
+LL |     println!("Hello world!");
+LL | }
    |
 
 error: this if statement can be collapsed
-  --> $DIR/collapsible_if.rs:20:5
+  --> $DIR/collapsible_if.rs:21:5
    |
-20 | /     if x == "hello" && x == "world" {
-21 | |         if y == "world" || y == "hello" {
-22 | |             println!("Hello world!");
-23 | |         }
-24 | |     }
+LL | /     if x == "hello" && x == "world" {
+LL | |         if y == "world" || y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-20 |     if x == "hello" && x == "world" && (y == "world" || y == "hello") {
-21 |     println!("Hello world!");
-22 | }
+LL |     if x == "hello" && x == "world" && (y == "world" || y == "hello") {
+LL |     println!("Hello world!");
+LL | }
    |
 
 error: this if statement can be collapsed
-  --> $DIR/collapsible_if.rs:26:5
+  --> $DIR/collapsible_if.rs:27:5
    |
-26 | /     if x == "hello" || x == "world" {
-27 | |         if y == "world" && y == "hello" {
-28 | |             println!("Hello world!");
-29 | |         }
-30 | |     }
+LL | /     if x == "hello" || x == "world" {
+LL | |         if y == "world" && y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-26 |     if (x == "hello" || x == "world") && y == "world" && y == "hello" {
-27 |     println!("Hello world!");
-28 | }
+LL |     if (x == "hello" || x == "world") && y == "world" && y == "hello" {
+LL |     println!("Hello world!");
+LL | }
    |
 
 error: this if statement can be collapsed
-  --> $DIR/collapsible_if.rs:32:5
+  --> $DIR/collapsible_if.rs:33:5
    |
-32 | /     if x == "hello" && x == "world" {
-33 | |         if y == "world" && y == "hello" {
-34 | |             println!("Hello world!");
-35 | |         }
-36 | |     }
+LL | /     if x == "hello" && x == "world" {
+LL | |         if y == "world" && y == "hello" {
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-32 |     if x == "hello" && x == "world" && y == "world" && y == "hello" {
-33 |     println!("Hello world!");
-34 | }
+LL |     if x == "hello" && x == "world" && y == "world" && y == "hello" {
+LL |     println!("Hello world!");
+LL | }
    |
 
 error: this if statement can be collapsed
-  --> $DIR/collapsible_if.rs:38:5
+  --> $DIR/collapsible_if.rs:39:5
    |
-38 | /     if 42 == 1337 {
-39 | |         if 'a' != 'A' {
-40 | |             println!("world!")
-41 | |         }
-42 | |     }
+LL | /     if 42 == 1337 {
+LL | |         if 'a' != 'A' {
+LL | |             println!("world!")
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-38 |     if 42 == 1337 && 'a' != 'A' {
-39 |     println!("world!")
-40 | }
+LL |     if 42 == 1337 && 'a' != 'A' {
+LL |     println!("world!")
+LL | }
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_if.rs:47:12
+  --> $DIR/collapsible_if.rs:48:12
    |
-47 |       } else {
+LL |       } else {
    |  ____________^
-48 | |         if y == "world" {
-49 | |             println!("world!")
-50 | |         }
-51 | |     }
+LL | |         if y == "world" {
+LL | |             println!("world!")
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-47 |     } else if y == "world" {
-48 |     println!("world!")
-49 | }
+LL |     } else if y == "world" {
+LL |     println!("world!")
+LL | }
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_if.rs:55:12
+  --> $DIR/collapsible_if.rs:56:12
    |
-55 |       } else {
+LL |       } else {
    |  ____________^
-56 | |         if let Some(42) = Some(42) {
-57 | |             println!("world!")
-58 | |         }
-59 | |     }
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world!")
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-55 |     } else if let Some(42) = Some(42) {
-56 |     println!("world!")
-57 | }
+LL |     } else if let Some(42) = Some(42) {
+LL |     println!("world!")
+LL | }
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_if.rs:63:12
+  --> $DIR/collapsible_if.rs:64:12
    |
-63 |       } else {
+LL |       } else {
    |  ____________^
-64 | |         if y == "world" {
-65 | |             println!("world")
-66 | |         }
+LL | |         if y == "world" {
+LL | |             println!("world")
+LL | |         }
 ...  |
-69 | |         }
-70 | |     }
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-63 |     } else if y == "world" {
-64 |     println!("world")
-65 | }
-66 | else {
-67 |     println!("!")
-68 | }
+LL |     } else if y == "world" {
+LL |     println!("world")
+LL | }
+LL | else {
+LL |     println!("!")
+LL | }
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_if.rs:74:12
+  --> $DIR/collapsible_if.rs:75:12
    |
-74 |       } else {
+LL |       } else {
    |  ____________^
-75 | |         if let Some(42) = Some(42) {
-76 | |             println!("world")
-77 | |         }
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world")
+LL | |         }
 ...  |
-80 | |         }
-81 | |     }
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-74 |     } else if let Some(42) = Some(42) {
-75 |     println!("world")
-76 | }
-77 | else {
-78 |     println!("!")
-79 | }
+LL |     } else if let Some(42) = Some(42) {
+LL |     println!("world")
+LL | }
+LL | else {
+LL |     println!("!")
+LL | }
    |
 
 error: this `else { if .. }` block can be collapsed
-  --> $DIR/collapsible_if.rs:85:12
+  --> $DIR/collapsible_if.rs:86:12
    |
-85 |       } else {
+LL |       } else {
    |  ____________^
-86 | |         if let Some(42) = Some(42) {
-87 | |             println!("world")
-88 | |         }
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world")
+LL | |         }
 ...  |
-91 | |         }
-92 | |     }
+LL | |         }
+LL | |     }
    | |_____^
 help: try
    |
-85 |     } else if let Some(42) = Some(42) {
-86 |     println!("world")
-87 | }
-88 | else {
-89 |     println!("!")
-90 | }
+LL |     } else if let Some(42) = Some(42) {
+LL |     println!("world")
+LL | }
+LL | else {
+LL |     println!("!")
+LL | }
    |
 
 error: this `else { if .. }` block can be collapsed
-   --> $DIR/collapsible_if.rs:96:12
-    |
-96  |       } else {
-    |  ____________^
-97  | |         if x == "hello" {
-98  | |             println!("world")
-99  | |         }
-...   |
-102 | |         }
-103 | |     }
-    | |_____^
+  --> $DIR/collapsible_if.rs:97:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if x == "hello" {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
 help: try
-    |
-96  |     } else if x == "hello" {
-97  |     println!("world")
-98  | }
-99  | else {
-100 |     println!("!")
-101 | }
-    |
+   |
+LL |     } else if x == "hello" {
+LL |     println!("world")
+LL | }
+LL | else {
+LL |     println!("!")
+LL | }
+   |
 
 error: this `else { if .. }` block can be collapsed
-   --> $DIR/collapsible_if.rs:107:12
-    |
-107 |       } else {
-    |  ____________^
-108 | |         if let Some(42) = Some(42) {
-109 | |             println!("world")
-110 | |         }
-...   |
-113 | |         }
-114 | |     }
-    | |_____^
+  --> $DIR/collapsible_if.rs:108:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         if let Some(42) = Some(42) {
+LL | |             println!("world")
+LL | |         }
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
 help: try
-    |
-107 |     } else if let Some(42) = Some(42) {
-108 |     println!("world")
-109 | }
-110 | else {
-111 |     println!("!")
-112 | }
-    |
+   |
+LL |     } else if let Some(42) = Some(42) {
+LL |     println!("world")
+LL | }
+LL | else {
+LL |     println!("!")
+LL | }
+   |
+
+error: this if statement can be collapsed
+  --> $DIR/collapsible_if.rs:167:5
+   |
+LL | /     if x == "hello" {
+LL | |         if y == "world" { // Collapsible
+LL | |             println!("Hello world!");
+LL | |         }
+LL | |     }
+   | |_____^
+help: try
+   |
+LL |     if x == "hello" && y == "world" { // Collapsible
+LL |     println!("Hello world!");
+LL | }
+   |
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
index 7719a7a86322b3d4cf57be14e32f6335bea4e136..be61fb6b9be613cca8bd66f622644b253af6cabd 100644 (file)
@@ -1,7 +1,5 @@
-
-
-#![warn(clippy)]
-#![allow(unused, needless_pass_by_value)]
+#![warn(clippy::all)]
+#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box)]
 #![feature(associated_type_defaults)]
 
 type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here
@@ -22,23 +20,41 @@ enum E {
 
 impl S {
     const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
-    fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { }
+    fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
 }
 
 trait T {
     const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
     type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
     fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
-    fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { }
+    fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
 }
 
-fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] }
+fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
+    vec![]
+}
 
-fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { }
+fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
 
 fn test3() {
     let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
 }
 
-fn main() {
+#[repr(C)]
+struct D {
+    // should not warn, since we don't have control over the signature (#3222)
+    test4: extern "C" fn(
+        itself: &D,
+        a: usize,
+        b: usize,
+        c: usize,
+        d: usize,
+        e: usize,
+        f: usize,
+        g: usize,
+        h: usize,
+        i: usize,
+    ),
 }
+
+fn main() {}
index 829a22c233f036334a04fbd4c2ff88b283c50eef..8f5dbd27956c5326e60aae886b8bc9ddd4cc2fb0 100644 (file)
@@ -1,93 +1,93 @@
 error: very complex type used. Consider factoring parts into `type` definitions
--> $DIR/complex_types.rs:9:12
-  |
-9 | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
-  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D type-complexity` implied by `-D warnings`
 --> $DIR/complex_types.rs:7:12
+   |
+LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::type-complexity` implied by `-D warnings`
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:10:12
+  --> $DIR/complex_types.rs:8:12
    |
-10 | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:13:8
+  --> $DIR/complex_types.rs:11:8
    |
-13 |     f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
+LL |     f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:16:11
+  --> $DIR/complex_types.rs:14:11
    |
-16 | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
+LL | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:19:11
+  --> $DIR/complex_types.rs:17:11
    |
-19 |     Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
+LL |     Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:20:17
+  --> $DIR/complex_types.rs:18:17
    |
-20 |     Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
+LL |     Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:24:14
+  --> $DIR/complex_types.rs:22:14
    |
-24 |     const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
+LL |     const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:25:30
+  --> $DIR/complex_types.rs:23:30
    |
-25 |     fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { }
+LL |     fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:29:14
+  --> $DIR/complex_types.rs:27:14
    |
-29 |     const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+LL |     const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:30:14
+  --> $DIR/complex_types.rs:28:14
    |
-30 |     type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
+LL |     type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:31:25
+  --> $DIR/complex_types.rs:29:25
    |
-31 |     fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
+LL |     fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:32:29
+  --> $DIR/complex_types.rs:30:29
    |
-32 |     fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { }
+LL |     fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
-  --> $DIR/complex_types.rs:35:15
+  --> $DIR/complex_types.rs:33:15
    |
-35 | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> { vec![] }
+LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
   --> $DIR/complex_types.rs:37:14
    |
-37 | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) { }
+LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: very complex type used. Consider factoring parts into `type` definitions
   --> $DIR/complex_types.rs:40:13
    |
-40 |     let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
+LL |     let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 15 previous errors
index db33744c7a9bf857bf2169f3167cc0d4dd5c144f..c329e860558e31741fab5e5ba9d1fd582457ec99 100644 (file)
@@ -1,81 +1,81 @@
 error: Constants have by default a `'static` lifetime
- --> $DIR/const_static_lifetime.rs:4:17
-  |
-4 | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
-  |                -^^^^^^^---- help: consider removing `'static`: `&str`
-  |
-  = note: `-D const-static-lifetime` implied by `-D warnings`
 --> $DIR/const_static_lifetime.rs:4:17
+   |
+LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
+   |                -^^^^^^^---- help: consider removing `'static`: `&str`
+   |
+   = note: `-D clippy::const-static-lifetime` implied by `-D warnings`
 
 error: Constants have by default a `'static` lifetime
- --> $DIR/const_static_lifetime.rs:8:21
-  |
-8 | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
-  |                    -^^^^^^^---- help: consider removing `'static`: `&str`
 --> $DIR/const_static_lifetime.rs:8:21
+   |
+LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
+   |                    -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:10:32
    |
-10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                               -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:10:47
    |
-10 | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
+LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:12:18
    |
-12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
    |                 -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:12:30
    |
-12 | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
+LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static
    |                             -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:14:17
    |
-14 | const VAR_SIX: &'static u8 = &5;
+LL | const VAR_SIX: &'static u8 = &5;
    |                -^^^^^^^--- help: consider removing `'static`: `&u8`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:16:29
    |
-16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
    |                            -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:16:39
    |
-16 | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
+LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])];
    |                                      -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:18:20
    |
-18 | const VAR_HEIGHT: &'static Foo = &Foo {};
+LL | const VAR_HEIGHT: &'static Foo = &Foo {};
    |                   -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:20:19
    |
-20 | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
+LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
    |                  -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:22:19
    |
-22 | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
+LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                  -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
 error: Constants have by default a `'static` lifetime
   --> $DIR/const_static_lifetime.rs:24:19
    |
-24 | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
+LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
    |                  -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
 error: aborting due to 13 previous errors
diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs
deleted file mode 100644 (file)
index 65a565c..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-#![allow(blacklisted_name, collapsible_if, cyclomatic_complexity, eq_op, needless_continue,
-         needless_return, never_loop, no_effect, zero_divided_by_zero)]
-
-fn bar<T>(_: T) {}
-fn foo() -> bool { unimplemented!() }
-
-struct Foo {
-    bar: u8,
-}
-
-pub enum Abc {
-    A,
-    B,
-    C,
-}
-
-#[warn(if_same_then_else)]
-#[warn(match_same_arms)]
-fn if_same_then_else() -> Result<&'static str, ()> {
-    if true {
-        Foo { bar: 42 };
-        0..10;
-        ..;
-        0..;
-        ..10;
-        0..=10;
-        foo();
-    }
-    else { //~ ERROR same body as `if` block
-        Foo { bar: 42 };
-        0..10;
-        ..;
-        0..;
-        ..10;
-        0..=10;
-        foo();
-    }
-
-    if true {
-        Foo { bar: 42 };
-    }
-    else {
-        Foo { bar: 43 };
-    }
-
-    if true {
-        ();
-    }
-    else {
-        ()
-    }
-
-    if true {
-        0..10;
-    }
-    else {
-        0..=10;
-    }
-
-    if true {
-        foo();
-        foo();
-    }
-    else {
-        foo();
-    }
-
-    let _ = match 42 {
-        42 => {
-            foo();
-            let mut a = 42 + [23].len() as i32;
-            if true {
-                a += 7;
-            }
-            a = -31-a;
-            a
-        }
-        _ => { //~ ERROR match arms have same body
-            foo();
-            let mut a = 42 + [23].len() as i32;
-            if true {
-                a += 7;
-            }
-            a = -31-a;
-            a
-        }
-    };
-
-    let _ = match Abc::A {
-        Abc::A => 0,
-        Abc::B => 1,
-        _ => 0, //~ ERROR match arms have same body
-    };
-
-    if true {
-        foo();
-    }
-
-    let _ = if true {
-        42
-    }
-    else { //~ ERROR same body as `if` block
-        42
-    };
-
-    if true {
-        for _ in &[42] {
-            let foo: &Option<_> = &Some::<u8>(42);
-            if true {
-                break;
-            } else {
-                continue;
-            }
-        }
-    }
-    else { //~ ERROR same body as `if` block
-        for _ in &[42] {
-            let foo: &Option<_> = &Some::<u8>(42);
-            if true {
-                break;
-            } else {
-                continue;
-            }
-        }
-    }
-
-    if true {
-        let bar = if true {
-            42
-        }
-        else {
-            43
-        };
-
-        while foo() { break; }
-        bar + 1;
-    }
-    else { //~ ERROR same body as `if` block
-        let bar = if true {
-            42
-        }
-        else {
-            43
-        };
-
-        while foo() { break; }
-        bar + 1;
-    }
-
-    if true {
-        let _ = match 42 {
-            42 => 1,
-            a if a > 0 => 2,
-            10..=15 => 3,
-            _ => 4,
-        };
-    }
-    else if false {
-        foo();
-    }
-    else if foo() {
-        let _ = match 42 {
-            42 => 1,
-            a if a > 0 => 2,
-            10..=15 => 3,
-            _ => 4,
-        };
-    }
-
-    if true {
-        if let Some(a) = Some(42) {}
-    }
-    else { //~ ERROR same body as `if` block
-        if let Some(a) = Some(42) {}
-    }
-
-    if true {
-        if let (1, .., 3) = (1, 2, 3) {}
-    }
-    else { //~ ERROR same body as `if` block
-        if let (1, .., 3) = (1, 2, 3) {}
-    }
-
-    if true {
-        if let (1, .., 3) = (1, 2, 3) {}
-    }
-    else {
-        if let (.., 3) = (1, 2, 3) {}
-    }
-
-    if true {
-        if let (1, .., 3) = (1, 2, 3) {}
-    }
-    else {
-        if let (.., 4) = (1, 2, 3) {}
-    }
-
-    if true {
-        if let (1, .., 3) = (1, 2, 3) {}
-    }
-    else {
-        if let (.., 1, 3) = (1, 2, 3) {}
-    }
-
-    if true {
-        if let Some(42) = None {}
-    }
-    else {
-        if let Option::Some(42) = None {}
-    }
-
-    if true {
-        if let Some(42) = None::<u8> {}
-    }
-    else {
-        if let Some(42) = None {}
-    }
-
-    if true {
-        if let Some(42) = None::<u8> {}
-    }
-    else {
-        if let Some(42) = None::<u32> {}
-    }
-
-    if true {
-        if let Some(a) = Some(42) {}
-    }
-    else {
-        if let Some(a) = Some(43) {}
-    }
-
-    let _ = match 42 {
-        42 => foo(),
-        51 => foo(), //~ ERROR match arms have same body
-        _ => true,
-    };
-
-    let _ = match Some(42) {
-        Some(_) => 24,
-        None => 24, //~ ERROR match arms have same body
-    };
-
-    let _ = match Some(42) {
-        Some(foo) => 24,
-        None => 24,
-    };
-
-    let _ = match Some(42) {
-        Some(42) => 24,
-        Some(a) => 24, // bindings are different
-        None => 0,
-    };
-
-    let _ = match Some(42) {
-        Some(a) if a > 0 => 24,
-        Some(a) => 24, // one arm has a guard
-        None => 0,
-    };
-
-    match (Some(42), Some(42)) {
-        (Some(a), None) => bar(a),
-        (None, Some(a)) => bar(a), //~ ERROR match arms have same body
-        _ => (),
-    }
-
-    match (Some(42), Some(42)) {
-        (Some(a), ..) => bar(a),
-        (.., Some(a)) => bar(a), //~ ERROR match arms have same body
-        _ => (),
-    }
-
-    match (1, 2, 3) {
-        (1, .., 3) => 42,
-        (.., 3) => 42, //~ ERROR match arms have same body
-        _ => 0,
-    };
-
-    let _ = if true {
-        0.0
-    } else { //~ ERROR same body as `if` block
-        0.0
-    };
-
-    let _ = if true {
-        -0.0
-    } else { //~ ERROR same body as `if` block
-        -0.0
-    };
-
-    let _ = if true {
-        0.0
-    } else {
-        -0.0
-    };
-
-    // Different NaNs
-    let _ = if true {
-        0.0 / 0.0
-    } else {
-        std::f32::NAN
-    };
-
-    // Same NaNs
-    let _ = if true {
-        std::f32::NAN
-    } else { //~ ERROR same body as `if` block
-        std::f32::NAN
-    };
-
-    let _ = match Some(()) {
-        Some(()) => 0.0,
-        None => -0.0
-    };
-
-    match (Some(42), Some("")) {
-        (Some(a), None) => bar(a),
-        (None, Some(a)) => bar(a), // bindings have different types
-        _ => (),
-    }
-
-    if true {
-        try!(Ok("foo"));
-    }
-    else { //~ ERROR same body as `if` block
-        try!(Ok("foo"));
-    }
-
-    if true {
-        let foo = "";
-        return Ok(&foo[0..]);
-    }
-    else if false {
-        let foo = "bar";
-        return Ok(&foo[0..]);
-    }
-    else {
-        let foo = "";
-        return Ok(&foo[0..]);
-    }
-}
-
-#[warn(ifs_same_cond)]
-#[allow(if_same_then_else)] // all empty blocks
-fn ifs_same_cond() {
-    let a = 0;
-    let b = false;
-
-    if b {
-    }
-    else if b { //~ ERROR ifs same condition
-    }
-
-    if a == 1 {
-    }
-    else if a == 1 { //~ ERROR ifs same condition
-    }
-
-    if 2*a == 1 {
-    }
-    else if 2*a == 2 {
-    }
-    else if 2*a == 1 { //~ ERROR ifs same condition
-    }
-    else if a == 1 {
-    }
-
-    // See #659
-    if cfg!(feature = "feature1-659") {
-        1
-    } else if cfg!(feature = "feature2-659") {
-        2
-    } else {
-        3
-    };
-
-    let mut v = vec![1];
-    if v.pop() == None { // ok, functions
-    }
-    else if v.pop() == None {
-    }
-
-    if v.len() == 42 { // ok, functions
-    }
-    else if v.len() == 42 {
-    }
-}
-
-fn main() {}
-
-// Issue #2423. This was causing an ICE
-fn func() {
-    if true {
-        f(&[0; 62]);
-        f(&[0; 4]);
-        f(&[0; 3]);
-    } else {
-        f(&[0; 62]);
-        f(&[0; 6]);
-        f(&[0; 6]);
-    }
-}
-
-fn f(val: &[u8]) {}
diff --git a/tests/ui/copies.stderr b/tests/ui/copies.stderr
deleted file mode 100644 (file)
index cce6328..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-error: this `if` has identical blocks
-  --> $DIR/copies.rs:29:10
-   |
-29 |       else { //~ ERROR same body as `if` block
-   |  __________^
-30 | |         Foo { bar: 42 };
-31 | |         0..10;
-32 | |         ..;
-...  |
-36 | |         foo();
-37 | |     }
-   | |_____^
-   |
-   = note: `-D if-same-then-else` implied by `-D warnings`
-note: same as this
-  --> $DIR/copies.rs:20:13
-   |
-20 |       if true {
-   |  _____________^
-21 | |         Foo { bar: 42 };
-22 | |         0..10;
-23 | |         ..;
-...  |
-27 | |         foo();
-28 | |     }
-   | |_____^
-
-error: this `match` has identical arm bodies
-  --> $DIR/copies.rs:78:14
-   |
-78 |           _ => { //~ ERROR match arms have same body
-   |  ______________^
-79 | |             foo();
-80 | |             let mut a = 42 + [23].len() as i32;
-81 | |             if true {
-...  |
-85 | |             a
-86 | |         }
-   | |_________^
-   |
-   = note: `-D match-same-arms` implied by `-D warnings`
-note: same as this
-  --> $DIR/copies.rs:69:15
-   |
-69 |           42 => {
-   |  _______________^
-70 | |             foo();
-71 | |             let mut a = 42 + [23].len() as i32;
-72 | |             if true {
-...  |
-76 | |             a
-77 | |         }
-   | |_________^
-note: `42` has the same arm body as the `_` wildcard, consider removing it`
-  --> $DIR/copies.rs:69:15
-   |
-69 |           42 => {
-   |  _______________^
-70 | |             foo();
-71 | |             let mut a = 42 + [23].len() as i32;
-72 | |             if true {
-...  |
-76 | |             a
-77 | |         }
-   | |_________^
-
-error: this `match` has identical arm bodies
-  --> $DIR/copies.rs:92:14
-   |
-92 |         _ => 0, //~ ERROR match arms have same body
-   |              ^
-   |
-note: same as this
-  --> $DIR/copies.rs:90:19
-   |
-90 |         Abc::A => 0,
-   |                   ^
-note: `Abc::A` has the same arm body as the `_` wildcard, consider removing it`
-  --> $DIR/copies.rs:90:19
-   |
-90 |         Abc::A => 0,
-   |                   ^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:102:10
-    |
-102 |       else { //~ ERROR same body as `if` block
-    |  __________^
-103 | |         42
-104 | |     };
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:99:21
-    |
-99  |       let _ = if true {
-    |  _____________________^
-100 | |         42
-101 | |     }
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:116:10
-    |
-116 |       else { //~ ERROR same body as `if` block
-    |  __________^
-117 | |         for _ in &[42] {
-118 | |             let foo: &Option<_> = &Some::<u8>(42);
-119 | |             if true {
-...   |
-124 | |         }
-125 | |     }
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:106:13
-    |
-106 |       if true {
-    |  _____________^
-107 | |         for _ in &[42] {
-108 | |             let foo: &Option<_> = &Some::<u8>(42);
-109 | |             if true {
-...   |
-114 | |         }
-115 | |     }
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:138:10
-    |
-138 |       else { //~ ERROR same body as `if` block
-    |  __________^
-139 | |         let bar = if true {
-140 | |             42
-141 | |         }
-...   |
-147 | |         bar + 1;
-148 | |     }
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:127:13
-    |
-127 |       if true {
-    |  _____________^
-128 | |         let bar = if true {
-129 | |             42
-130 | |         }
-...   |
-136 | |         bar + 1;
-137 | |     }
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:173:10
-    |
-173 |       else { //~ ERROR same body as `if` block
-    |  __________^
-174 | |         if let Some(a) = Some(42) {}
-175 | |     }
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:170:13
-    |
-170 |       if true {
-    |  _____________^
-171 | |         if let Some(a) = Some(42) {}
-172 | |     }
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:180:10
-    |
-180 |       else { //~ ERROR same body as `if` block
-    |  __________^
-181 | |         if let (1, .., 3) = (1, 2, 3) {}
-182 | |     }
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:177:13
-    |
-177 |       if true {
-    |  _____________^
-178 | |         if let (1, .., 3) = (1, 2, 3) {}
-179 | |     }
-    | |_____^
-
-error: this `match` has identical arm bodies
-   --> $DIR/copies.rs:235:15
-    |
-235 |         51 => foo(), //~ ERROR match arms have same body
-    |               ^^^^^
-    |
-note: same as this
-   --> $DIR/copies.rs:234:15
-    |
-234 |         42 => foo(),
-    |               ^^^^^
-note: consider refactoring into `42 | 51`
-   --> $DIR/copies.rs:234:15
-    |
-234 |         42 => foo(),
-    |               ^^^^^
-
-error: this `match` has identical arm bodies
-   --> $DIR/copies.rs:241:17
-    |
-241 |         None => 24, //~ ERROR match arms have same body
-    |                 ^^
-    |
-note: same as this
-   --> $DIR/copies.rs:240:20
-    |
-240 |         Some(_) => 24,
-    |                    ^^
-note: consider refactoring into `Some(_) | None`
-   --> $DIR/copies.rs:240:20
-    |
-240 |         Some(_) => 24,
-    |                    ^^
-
-error: this `match` has identical arm bodies
-   --> $DIR/copies.rs:263:28
-    |
-263 |         (None, Some(a)) => bar(a), //~ ERROR match arms have same body
-    |                            ^^^^^^
-    |
-note: same as this
-   --> $DIR/copies.rs:262:28
-    |
-262 |         (Some(a), None) => bar(a),
-    |                            ^^^^^^
-note: consider refactoring into `(Some(a), None) | (None, Some(a))`
-   --> $DIR/copies.rs:262:28
-    |
-262 |         (Some(a), None) => bar(a),
-    |                            ^^^^^^
-
-error: this `match` has identical arm bodies
-   --> $DIR/copies.rs:269:26
-    |
-269 |         (.., Some(a)) => bar(a), //~ ERROR match arms have same body
-    |                          ^^^^^^
-    |
-note: same as this
-   --> $DIR/copies.rs:268:26
-    |
-268 |         (Some(a), ..) => bar(a),
-    |                          ^^^^^^
-note: consider refactoring into `(Some(a), ..) | (.., Some(a))`
-   --> $DIR/copies.rs:268:26
-    |
-268 |         (Some(a), ..) => bar(a),
-    |                          ^^^^^^
-
-error: this `match` has identical arm bodies
-   --> $DIR/copies.rs:275:20
-    |
-275 |         (.., 3) => 42, //~ ERROR match arms have same body
-    |                    ^^
-    |
-note: same as this
-   --> $DIR/copies.rs:274:23
-    |
-274 |         (1, .., 3) => 42,
-    |                       ^^
-note: consider refactoring into `(1, .., 3) | (.., 3)`
-   --> $DIR/copies.rs:274:23
-    |
-274 |         (1, .., 3) => 42,
-    |                       ^^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:281:12
-    |
-281 |       } else { //~ ERROR same body as `if` block
-    |  ____________^
-282 | |         0.0
-283 | |     };
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:279:21
-    |
-279 |       let _ = if true {
-    |  _____________________^
-280 | |         0.0
-281 | |     } else { //~ ERROR same body as `if` block
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:287:12
-    |
-287 |       } else { //~ ERROR same body as `if` block
-    |  ____________^
-288 | |         -0.0
-289 | |     };
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:285:21
-    |
-285 |       let _ = if true {
-    |  _____________________^
-286 | |         -0.0
-287 | |     } else { //~ ERROR same body as `if` block
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:307:12
-    |
-307 |       } else { //~ ERROR same body as `if` block
-    |  ____________^
-308 | |         std::f32::NAN
-309 | |     };
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:305:21
-    |
-305 |       let _ = if true {
-    |  _____________________^
-306 | |         std::f32::NAN
-307 | |     } else { //~ ERROR same body as `if` block
-    | |_____^
-
-error: this `if` has identical blocks
-   --> $DIR/copies.rs:325:10
-    |
-325 |       else { //~ ERROR same body as `if` block
-    |  __________^
-326 | |         try!(Ok("foo"));
-327 | |     }
-    | |_____^
-    |
-note: same as this
-   --> $DIR/copies.rs:322:13
-    |
-322 |       if true {
-    |  _____________^
-323 | |         try!(Ok("foo"));
-324 | |     }
-    | |_____^
-
-error: this `if` has the same condition as a previous if
-   --> $DIR/copies.rs:351:13
-    |
-351 |     else if b { //~ ERROR ifs same condition
-    |             ^
-    |
-    = note: `-D ifs-same-cond` implied by `-D warnings`
-note: same as this
-   --> $DIR/copies.rs:349:8
-    |
-349 |     if b {
-    |        ^
-
-error: this `if` has the same condition as a previous if
-   --> $DIR/copies.rs:356:13
-    |
-356 |     else if a == 1 { //~ ERROR ifs same condition
-    |             ^^^^^^
-    |
-note: same as this
-   --> $DIR/copies.rs:354:8
-    |
-354 |     if a == 1 {
-    |        ^^^^^^
-
-error: this `if` has the same condition as a previous if
-   --> $DIR/copies.rs:363:13
-    |
-363 |     else if 2*a == 1 { //~ ERROR ifs same condition
-    |             ^^^^^^^^
-    |
-note: same as this
-   --> $DIR/copies.rs:359:8
-    |
-359 |     if 2*a == 1 {
-    |        ^^^^^^^^
-
-error: aborting due to 20 previous errors
-
diff --git a/tests/ui/copy_iterator.rs b/tests/ui/copy_iterator.rs
new file mode 100644 (file)
index 0000000..e3d5928
--- /dev/null
@@ -0,0 +1,23 @@
+#![warn(clippy::copy_iterator)]
+
+#[derive(Copy, Clone)]
+struct Countdown(u8);
+
+impl Iterator for Countdown {
+    type Item = u8;
+
+    fn next(&mut self) -> Option<u8> {
+        self.0.checked_sub(1).map(|c| {
+            self.0 = c;
+            c
+        })
+    }
+}
+
+fn main() {
+    let my_iterator = Countdown(5);
+    let a: Vec<_> = my_iterator.take(1).collect();
+    assert_eq!(a.len(), 1);
+    let b: Vec<_> = my_iterator.collect();
+    assert_eq!(b.len(), 5);
+}
diff --git a/tests/ui/copy_iterator.stderr b/tests/ui/copy_iterator.stderr
new file mode 100644 (file)
index 0000000..f8ce6af
--- /dev/null
@@ -0,0 +1,17 @@
+error: you are implementing `Iterator` on a `Copy` type
+  --> $DIR/copy_iterator.rs:6:1
+   |
+LL | / impl Iterator for Countdown {
+LL | |     type Item = u8;
+LL | |
+LL | |     fn next(&mut self) -> Option<u8> {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::copy-iterator` implied by `-D warnings`
+   = note: consider implementing `IntoIterator` instead
+
+error: aborting due to previous error
+
diff --git a/tests/ui/crashes/associated-constant-ice.rs b/tests/ui/crashes/associated-constant-ice.rs
new file mode 100644 (file)
index 0000000..4bb8337
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1698
+
+pub trait Trait {
+    const CONSTANT: u8;
+}
+
+impl Trait for u8 {
+    const CONSTANT: u8 = 2;
+}
+
+fn main() {
+    println!("{}", u8::CONSTANT * 10);
+}
diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs
new file mode 100644 (file)
index 0000000..71b10ed
--- /dev/null
@@ -0,0 +1,37 @@
+// no-prefer-dynamic
+// ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
+// crates. If we don't set this, compiletest will override the `crate_type` attribute below and
+// compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't
+// contain a proc-macro.
+
+#![feature(repr128)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
+use std::iter::FromIterator;
+
+#[proc_macro]
+pub fn macro_test(input_stream: TokenStream) -> TokenStream {
+    let first_token = input_stream.into_iter().next().unwrap();
+    let span = first_token.span();
+
+    TokenStream::from_iter(vec![
+        TokenTree::Ident(Ident::new("fn", Span::call_site())),
+        TokenTree::Ident(Ident::new("code", Span::call_site())),
+        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
+        TokenTree::Group(Group::new(Delimiter::Brace, {
+            let mut clause = Group::new(Delimiter::Brace, TokenStream::new());
+            clause.set_span(span);
+
+            TokenStream::from_iter(vec![
+                TokenTree::Ident(Ident::new("if", Span::call_site())),
+                TokenTree::Ident(Ident::new("true", Span::call_site())),
+                TokenTree::Group(clause.clone()),
+                TokenTree::Ident(Ident::new("else", Span::call_site())),
+                TokenTree::Group(clause.clone()),
+            ])
+        })),
+    ])
+}
diff --git a/tests/ui/crashes/cc_seme.rs b/tests/ui/crashes/cc_seme.rs
new file mode 100644 (file)
index 0000000..c48c7e9
--- /dev/null
@@ -0,0 +1,29 @@
+// run-pass
+
+#[allow(dead_code)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/478
+
+enum Baz {
+    One,
+    Two,
+}
+
+struct Test {
+    t: Option<usize>,
+    b: Baz,
+}
+
+fn main() {}
+
+pub fn foo() {
+    use Baz::*;
+    let x = Test { t: Some(0), b: One };
+
+    match x {
+        Test { t: Some(_), b: One } => unreachable!(),
+        Test { t: Some(42), b: Two } => unreachable!(),
+        Test { t: None, .. } => unreachable!(),
+        Test { .. } => unreachable!(),
+    }
+}
diff --git a/tests/ui/crashes/enum-glob-import-crate.rs b/tests/ui/crashes/enum-glob-import-crate.rs
new file mode 100644 (file)
index 0000000..db1fa87
--- /dev/null
@@ -0,0 +1,8 @@
+// run-pass
+
+#![deny(clippy::all)]
+#![allow(unused_imports)]
+
+use std::*;
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-1588.rs b/tests/ui/crashes/ice-1588.rs
new file mode 100644 (file)
index 0000000..15d0f70
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+
+#![allow(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1588
+
+fn main() {
+    match 1 {
+        1 => {},
+        2 => {
+            [0; 1];
+        },
+        _ => {},
+    }
+}
diff --git a/tests/ui/crashes/ice-1782.rs b/tests/ui/crashes/ice-1782.rs
new file mode 100644 (file)
index 0000000..1ca6b69
--- /dev/null
@@ -0,0 +1,28 @@
+// run-pass
+
+#![allow(dead_code, unused_variables)]
+
+/// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
+///
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/1782
+use std::{mem, ptr};
+
+fn spanless_eq_ice() {
+    let txt = "something";
+    match txt {
+        "something" => unsafe {
+            ptr::write(
+                ptr::null_mut() as *mut u32,
+                mem::transmute::<[u8; 4], _>([0, 0, 0, 255]),
+            )
+        },
+        _ => unsafe {
+            ptr::write(
+                ptr::null_mut() as *mut u32,
+                mem::transmute::<[u8; 4], _>([13, 246, 24, 255]),
+            )
+        },
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-1969.rs b/tests/ui/crashes/ice-1969.rs
new file mode 100644 (file)
index 0000000..837ec9d
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+
+#![allow(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1969
+
+fn main() {}
+
+pub trait Convert {
+    type Action: From<*const f64>;
+
+    fn convert(val: *const f64) -> Self::Action {
+        val.into()
+    }
+}
diff --git a/tests/ui/crashes/ice-2499.rs b/tests/ui/crashes/ice-2499.rs
new file mode 100644 (file)
index 0000000..ffef163
--- /dev/null
@@ -0,0 +1,28 @@
+// run-pass
+
+#![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
+
+/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
+///
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/2499
+
+fn f(s: &[u8]) -> bool {
+    let t = s[0] as char;
+
+    match t {
+        'E' | 'W' => {},
+        'T' => {
+            if s[0..4] != ['0' as u8; 4] {
+                return false;
+            } else {
+                return true;
+            }
+        },
+        _ => {
+            return false;
+        },
+    }
+    true
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-2594.rs b/tests/ui/crashes/ice-2594.rs
new file mode 100644 (file)
index 0000000..ac19f19
--- /dev/null
@@ -0,0 +1,22 @@
+// run-pass
+
+#![allow(dead_code, unused_variables)]
+
+/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
+///
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/2594
+
+fn spanless_hash_ice() {
+    let txt = "something";
+    let empty_header: [u8; 1] = [1; 1];
+
+    match txt {
+        "something" => {
+            let mut headers = [empty_header; 1];
+        },
+        "" => (),
+        _ => (),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-2727.rs b/tests/ui/crashes/ice-2727.rs
new file mode 100644 (file)
index 0000000..d832c28
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2727
+
+pub fn f(new: fn()) {
+    new();
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs
new file mode 100644 (file)
index 0000000..9e5e299
--- /dev/null
@@ -0,0 +1,25 @@
+// run-pass
+
+#![allow(
+    unused_variables,
+    clippy::blacklisted_name,
+    clippy::needless_pass_by_value,
+    dead_code
+)]
+
+/// This should not compile-fail with:
+///
+///      error[E0277]: the trait bound `T: Foo` is not satisfied
+// See rust-lang/rust-clippy#2760.
+
+trait Foo {
+    type Bar;
+}
+
+struct Baz<T: Foo> {
+    bar: T::Bar,
+}
+
+fn take<T: Foo>(baz: Baz<T>) {}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-2774.rs b/tests/ui/crashes/ice-2774.rs
new file mode 100644 (file)
index 0000000..47f8e3b
--- /dev/null
@@ -0,0 +1,29 @@
+// run-pass
+
+use std::collections::HashSet;
+
+// See rust-lang/rust-clippy#2774.
+
+#[derive(Eq, PartialEq, Debug, Hash)]
+pub struct Bar {
+    foo: Foo,
+}
+
+#[derive(Eq, PartialEq, Debug, Hash)]
+pub struct Foo {}
+
+#[allow(clippy::implicit_hasher)]
+// This should not cause a "cannot relate bound region" ICE.
+pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+    let mut foos = HashSet::new();
+    foos.extend(bars.iter().map(|b| &b.foo));
+}
+
+#[allow(clippy::implicit_hasher)]
+// Also, this should not cause a "cannot relate bound region" ICE.
+pub fn add_barfoos_to_foos2(bars: &HashSet<&Bar>) {
+    let mut foos = HashSet::new();
+    foos.extend(bars.iter().map(|b| &b.foo));
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-2865.rs b/tests/ui/crashes/ice-2865.rs
new file mode 100644 (file)
index 0000000..c4f6c0f
--- /dev/null
@@ -0,0 +1,18 @@
+// run-pass
+
+#[allow(dead_code)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
+
+struct Ice {
+    size: String,
+}
+
+impl<'a> From<String> for Ice {
+    fn from(_: String) -> Self {
+        let text = || "iceberg".to_string();
+        Self { size: text() }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-3151.rs b/tests/ui/crashes/ice-3151.rs
new file mode 100644 (file)
index 0000000..ffad2d0
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
+
+#[derive(Clone)]
+pub struct HashMap<V, S> {
+    hash_builder: S,
+    table: RawTable<V>,
+}
+
+#[derive(Clone)]
+pub struct RawTable<V> {
+    size: usize,
+    val: V,
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs
new file mode 100644 (file)
index 0000000..95c7dff
--- /dev/null
@@ -0,0 +1,25 @@
+// run-pass
+
+#![warn(clippy::all)]
+#![allow(clippy::blacklisted_name)]
+#![allow(unused)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/3462
+
+enum Foo {
+    Bar,
+    Baz,
+}
+
+fn bar(foo: Foo) {
+    macro_rules! baz {
+        () => {
+            if let Foo::Bar = foo {}
+        };
+    }
+
+    baz!();
+    baz!();
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs
new file mode 100644 (file)
index 0000000..74b9c9c
--- /dev/null
@@ -0,0 +1,12 @@
+// aux-build:proc_macro_crash.rs
+// run-pass
+
+#![feature(proc_macro_hygiene)]
+#![warn(clippy::suspicious_else_formatting)]
+
+extern crate proc_macro_crash;
+use proc_macro_crash::macro_test;
+
+fn main() {
+    macro_test!(2);
+}
diff --git a/tests/ui/crashes/ice-3747.rs b/tests/ui/crashes/ice-3747.rs
new file mode 100644 (file)
index 0000000..d0b44eb
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/3747
+
+macro_rules! a {
+    ( $pub:tt $($attr:tt)* ) => {
+        $($attr)* $pub fn say_hello() {}
+    };
+}
+
+macro_rules! b {
+    () => {
+        a! { pub }
+    };
+}
+
+b! {}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-3891.rs b/tests/ui/crashes/ice-3891.rs
new file mode 100644 (file)
index 0000000..05c5134
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    1x;
+}
diff --git a/tests/ui/crashes/ice-3891.stderr b/tests/ui/crashes/ice-3891.stderr
new file mode 100644 (file)
index 0000000..16aedbd
--- /dev/null
@@ -0,0 +1,10 @@
+error: invalid suffix `x` for numeric literal
+  --> $DIR/ice-3891.rs:2:5
+   |
+LL |     1x;
+   |     ^^ invalid suffix `x`
+   |
+   = help: the suffix must be one of the integral types (`u32`, `isize`, etc)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/crashes/ice-700.rs b/tests/ui/crashes/ice-700.rs
new file mode 100644 (file)
index 0000000..b06df83
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+
+#![deny(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/700
+
+fn core() {}
+
+fn main() {
+    core();
+}
diff --git a/tests/ui/crashes/ice_exacte_size.rs b/tests/ui/crashes/ice_exacte_size.rs
new file mode 100644 (file)
index 0000000..e02eb28
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+
+#![deny(clippy::all)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1336
+
+#[allow(dead_code)]
+struct Foo;
+
+impl Iterator for Foo {
+    type Item = ();
+
+    fn next(&mut self) -> Option<()> {
+        let _ = self.len() == 0;
+        unimplemented!()
+    }
+}
+
+impl ExactSizeIterator for Foo {}
+
+fn main() {}
diff --git a/tests/ui/crashes/if_same_then_else.rs b/tests/ui/crashes/if_same_then_else.rs
new file mode 100644 (file)
index 0000000..b2a4d54
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+#![deny(clippy::if_same_then_else)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2426
+
+fn main() {}
+
+pub fn foo(a: i32, b: i32) -> Option<&'static str> {
+    if a == b {
+        None
+    } else if a > b {
+        Some("a pfeil b")
+    } else {
+        None
+    }
+}
diff --git a/tests/ui/crashes/issue-2862.rs b/tests/ui/crashes/issue-2862.rs
new file mode 100644 (file)
index 0000000..3587a08
--- /dev/null
@@ -0,0 +1,18 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2826
+
+pub trait FooMap {
+    fn map<B, F: Fn() -> B>(&self, f: F) -> B;
+}
+
+impl FooMap for bool {
+    fn map<B, F: Fn() -> B>(&self, f: F) -> B {
+        f()
+    }
+}
+
+fn main() {
+    let a = true;
+    a.map(|| false);
+}
diff --git a/tests/ui/crashes/issue-825.rs b/tests/ui/crashes/issue-825.rs
new file mode 100644 (file)
index 0000000..3d4a88a
--- /dev/null
@@ -0,0 +1,27 @@
+// run-pass
+
+#![allow(warnings)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/825
+
+// this should compile in a reasonable amount of time
+fn rust_type_id(name: &str) {
+    if "bool" == &name[..]
+        || "uint" == &name[..]
+        || "u8" == &name[..]
+        || "u16" == &name[..]
+        || "u32" == &name[..]
+        || "f32" == &name[..]
+        || "f64" == &name[..]
+        || "i8" == &name[..]
+        || "i16" == &name[..]
+        || "i32" == &name[..]
+        || "i64" == &name[..]
+        || "Self" == &name[..]
+        || "str" == &name[..]
+    {
+        unreachable!();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/issues_loop_mut_cond.rs b/tests/ui/crashes/issues_loop_mut_cond.rs
new file mode 100644 (file)
index 0000000..c4acd5c
--- /dev/null
@@ -0,0 +1,30 @@
+// run-pass
+
+#![allow(dead_code)]
+
+/// Issue: https://github.com/rust-lang/rust-clippy/issues/2596
+pub fn loop_on_block_condition(u: &mut isize) {
+    while { *u < 0 } {
+        *u += 1;
+    }
+}
+
+/// https://github.com/rust-lang/rust-clippy/issues/2584
+fn loop_with_unsafe_condition(ptr: *const u8) {
+    let mut len = 0;
+    while unsafe { *ptr.offset(len) } != 0 {
+        len += 1;
+    }
+}
+
+/// https://github.com/rust-lang/rust-clippy/issues/2710
+static mut RUNNING: bool = true;
+fn loop_on_static_condition() {
+    unsafe {
+        while RUNNING {
+            RUNNING = false;
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/match_same_arms_const.rs b/tests/ui/crashes/match_same_arms_const.rs
new file mode 100644 (file)
index 0000000..848f0ea
--- /dev/null
@@ -0,0 +1,20 @@
+// run-pass
+
+#![deny(clippy::match_same_arms)]
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/2427
+
+const PRICE_OF_SWEETS: u32 = 5;
+const PRICE_OF_KINDNESS: u32 = 0;
+const PRICE_OF_DRINKS: u32 = 5;
+
+pub fn price(thing: &str) -> u32 {
+    match thing {
+        "rolo" => PRICE_OF_SWEETS,
+        "advice" => PRICE_OF_KINDNESS,
+        "juice" => PRICE_OF_DRINKS,
+        _ => panic!(),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/mut_mut_macro.rs b/tests/ui/crashes/mut_mut_macro.rs
new file mode 100644 (file)
index 0000000..14219f5
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+
+#![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)]
+#![allow(dead_code)]
+
+// FIXME: compiletest + extern crates doesn't work together. To make this test work, it would need
+// the following three lines and the lazy_static crate.
+//
+//     #[macro_use]
+//     extern crate lazy_static;
+//     use std::collections::HashMap;
+
+/// ensure that we don't suggest `is_nan` and `is_null` inside constants
+/// FIXME: once const fn is stable, suggest these functions again in constants
+
+const BAA: *const i32 = 0 as *const i32;
+static mut BAR: *const i32 = BAA;
+static mut FOO: *const i32 = 0 as *const i32;
+static mut BUH: bool = 42.0 < std::f32::NAN;
+
+#[allow(unused_variables, unused_mut)]
+fn main() {
+    /*
+    lazy_static! {
+        static ref MUT_MAP : HashMap<usize, &'static str> = {
+            let mut m = HashMap::new();
+            m.insert(0, "zero");
+            m
+        };
+        static ref MUT_COUNT : usize = MUT_MAP.len();
+    }
+    assert_eq!(*MUT_COUNT, 1);
+    */
+    // FIXME: don't lint in array length, requires `check_body`
+    //let _ = [""; (42.0 < std::f32::NAN) as usize];
+}
diff --git a/tests/ui/crashes/needless_borrow_fp.rs b/tests/ui/crashes/needless_borrow_fp.rs
new file mode 100644 (file)
index 0000000..48507ef
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+
+#[deny(clippy::all)]
+#[derive(Debug)]
+pub enum Error {
+    Type(&'static str),
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/tests/ui/crashes/needless_lifetimes_impl_trait.rs
new file mode 100644 (file)
index 0000000..bd1fa4a
--- /dev/null
@@ -0,0 +1,22 @@
+// run-pass
+
+#![deny(clippy::needless_lifetimes)]
+#![allow(dead_code)]
+
+trait Foo {}
+
+struct Bar {}
+
+struct Baz<'a> {
+    bar: &'a Bar,
+}
+
+impl<'a> Foo for Baz<'a> {}
+
+impl Bar {
+    fn baz<'a>(&'a self) -> impl Foo + 'a {
+        Baz { bar: self }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/procedural_macro.rs b/tests/ui/crashes/procedural_macro.rs
new file mode 100644 (file)
index 0000000..f79d9ab
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+
+#[macro_use]
+extern crate clippy_mini_macro_test;
+
+#[deny(warnings)]
+fn main() {
+    let x = Foo;
+    println!("{:?}", x);
+}
+
+#[derive(ClippyMiniMacroTest, Debug)]
+struct Foo;
diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs
new file mode 100644 (file)
index 0000000..623ae51
--- /dev/null
@@ -0,0 +1,9 @@
+// run-pass
+
+#![allow(clippy::blacklisted_name)]
+
+pub fn foo(bar: *const u8) {
+    println!("{:#p}", bar);
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/returns.rs b/tests/ui/crashes/returns.rs
new file mode 100644 (file)
index 0000000..f2153ef
--- /dev/null
@@ -0,0 +1,25 @@
+// run-pass
+
+/// Test for https://github.com/rust-lang/rust-clippy/issues/1346
+
+#[deny(warnings)]
+fn cfg_return() -> i32 {
+    #[cfg(unix)]
+    return 1;
+    #[cfg(not(unix))]
+    return 2;
+}
+
+#[deny(warnings)]
+fn cfg_let_and_return() -> i32 {
+    #[cfg(unix)]
+    let x = 1;
+    #[cfg(not(unix))]
+    let x = 2;
+    x
+}
+
+fn main() {
+    cfg_return();
+    cfg_let_and_return();
+}
diff --git a/tests/ui/crashes/single-match-else.rs b/tests/ui/crashes/single-match-else.rs
new file mode 100644 (file)
index 0000000..3a4bbe3
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+
+#![warn(clippy::single_match_else)]
+
+//! Test for https://github.com/rust-lang/rust-clippy/issues/1588
+
+fn main() {
+    let n = match (42, 43) {
+        (42, n) => n,
+        _ => panic!("typeck error"),
+    };
+    assert_eq!(n, 43);
+}
diff --git a/tests/ui/crashes/used_underscore_binding_macro.rs b/tests/ui/crashes/used_underscore_binding_macro.rs
new file mode 100644 (file)
index 0000000..265017c
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+
+#![allow(clippy::useless_attribute)] //issue #2910
+
+#[macro_use]
+extern crate serde_derive;
+
+/// Tests that we do not lint for unused underscores in a `MacroAttribute`
+/// expansion
+#[deny(clippy::used_underscore_binding)]
+#[derive(Deserialize)]
+struct MacroAttributesTest {
+    _foo: u32,
+}
+
+#[test]
+fn macro_attributes_test() {
+    let _ = MacroAttributesTest { _foo: 0 };
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/whitelist/clippy.toml b/tests/ui/crashes/whitelist/clippy.toml
new file mode 100644 (file)
index 0000000..9f87de2
--- /dev/null
@@ -0,0 +1,3 @@
+# this is ignored by Clippy, but allowed for other tools like clippy-service
+[third-party]
+clippy-feature = "nightly"
diff --git a/tests/ui/crashes/whitelist/conf_whitelisted.rs b/tests/ui/crashes/whitelist/conf_whitelisted.rs
new file mode 100644 (file)
index 0000000..f328e4d
--- /dev/null
@@ -0,0 +1 @@
+fn main() {}
index 8b7b0b66bc6a8cad4617bbbe7eea3ef16ada6ac0..6cc36518e27ba7be4f817bc693c4de96bafb353d 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {}
 
-#[allow(result_unwrap_used)]
+#[allow(clippy::result_unwrap_used)]
 fn temporary_cstring() {
     use std::ffi::CString;
 
index 0e90f6963574100590f9d7b32c2e803037bcb0cc..a2fc07d4af0dff604c374cfe9f786686be66e1f4 100644 (file)
@@ -1,16 +1,16 @@
 error: you are getting the inner pointer of a temporary `CString`
- --> $DIR/cstring.rs:7:5
-  |
-7 |     CString::new("foo").unwrap().as_ptr();
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: #[deny(temporary_cstring_as_ptr)] on by default
-  = note: that pointer will be invalid outside this expression
 --> $DIR/cstring.rs:7:5
+   |
+LL |     CString::new("foo").unwrap().as_ptr();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[deny(clippy::temporary_cstring_as_ptr)] on by default
+   = note: that pointer will be invalid outside this expression
 help: assign the `CString` to a variable to extend its lifetime
- --> $DIR/cstring.rs:7:5
-  |
-7 |     CString::new("foo").unwrap().as_ptr();
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 --> $DIR/cstring.rs:7:5
+   |
+LL |     CString::new("foo").unwrap().as_ptr();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs
deleted file mode 100644 (file)
index 3214505..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-#![feature(tool_attributes)]
-
-#![allow(clippy)]
-#![warn(cyclomatic_complexity)]
-#![allow(unused)]
-
-fn main() {
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-    if true {
-        println!("a");
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn kaboom() {
-    let n = 0;
-    'a: for i in 0..20 {
-        'b: for j in i..20 {
-            for k in j..20 {
-                if k == 5 {
-                    break 'b;
-                }
-                if j == 3 && k == 6 {
-                    continue 'a;
-                }
-                if k == j {
-                    continue;
-                }
-                println!("bake");
-            }
-        }
-        println!("cake");
-    }
-}
-
-fn bloo() {
-    match 42 {
-        0 => println!("hi"),
-        1 => println!("hai"),
-        2 => println!("hey"),
-        3 => println!("hallo"),
-        4 => println!("hello"),
-        5 => println!("salut"),
-        6 => println!("good morning"),
-        7 => println!("good evening"),
-        8 => println!("good afternoon"),
-        9 => println!("good night"),
-        10 => println!("bonjour"),
-        11 => println!("hej"),
-        12 => println!("hej hej"),
-        13 => println!("greetings earthling"),
-        14 => println!("take us to you leader"),
-        15 | 17 | 19 | 21 | 23 | 25 | 27 | 29 | 31 | 33 => println!("take us to you leader"),
-        35 | 37 | 39 | 41 | 43 | 45 | 47 | 49 | 51 | 53 => println!("there is no undefined behavior"),
-        55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 73 => println!("I know borrow-fu"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn lots_of_short_circuits() -> bool {
-    true && false && true && false && true && false && true
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn lots_of_short_circuits2() -> bool {
-    true || false || true || false || true || false || true
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn baa() {
-    let x = || match 99 {
-        0 => 0,
-        1 => 1,
-        2 => 2,
-        4 => 4,
-        6 => 6,
-        9 => 9,
-        _ => 42,
-    };
-    if x() == 42 {
-        println!("x");
-    } else {
-        println!("not x");
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn bar() {
-    match 99 {
-        0 => println!("hi"),
-        _ => println!("bye"),
-    }
-}
-
-#[test]
-#[clippy::cyclomatic_complexity = "0"]
-/// Tests are usually complex but simple at the same time. `cyclomatic_complexity` used to give
-/// lots of false-positives in tests.
-fn dont_warn_on_tests() {
-    match 99 {
-        0 => println!("hi"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn barr() {
-    match 99 {
-        0 => println!("hi"),
-        1 => println!("bla"),
-        2 | 3 => println!("blub"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn barr2() {
-    match 99 {
-        0 => println!("hi"),
-        1 => println!("bla"),
-        2 | 3 => println!("blub"),
-        _ => println!("bye"),
-    }
-    match 99 {
-        0 => println!("hi"),
-        1 => println!("bla"),
-        2 | 3 => println!("blub"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn barrr() {
-    match 99 {
-        0 => println!("hi"),
-        1 => panic!("bla"),
-        2 | 3 => println!("blub"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn barrr2() {
-    match 99 {
-        0 => println!("hi"),
-        1 => panic!("bla"),
-        2 | 3 => println!("blub"),
-        _ => println!("bye"),
-    }
-    match 99 {
-        0 => println!("hi"),
-        1 => panic!("bla"),
-        2 | 3 => println!("blub"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn barrrr() {
-    match 99 {
-        0 => println!("hi"),
-        1 => println!("bla"),
-        2 | 3 => panic!("blub"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn barrrr2() {
-    match 99 {
-        0 => println!("hi"),
-        1 => println!("bla"),
-        2 | 3 => panic!("blub"),
-        _ => println!("bye"),
-    }
-    match 99 {
-        0 => println!("hi"),
-        1 => println!("bla"),
-        2 | 3 => panic!("blub"),
-        _ => println!("bye"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn cake() {
-    if 4 == 5 {
-        println!("yea");
-    } else {
-        panic!("meh");
-    }
-    println!("whee");
-}
-
-
-#[clippy::cyclomatic_complexity = "0"]
-pub fn read_file(input_path: &str) -> String {
-    use std::fs::File;
-    use std::io::{Read, Write};
-    use std::path::Path;
-    let mut file = match File::open(&Path::new(input_path)) {
-        Ok(f) => f,
-        Err(err) => {
-            panic!("Can't open {}: {}", input_path, err);
-        }
-    };
-
-    let mut bytes = Vec::new();
-
-    match file.read_to_end(&mut bytes) {
-        Ok(..) => {},
-        Err(_) => {
-            panic!("Can't read {}", input_path);
-        }
-    };
-
-    match String::from_utf8(bytes) {
-        Ok(contents) => contents,
-        Err(_) => {
-            panic!("{} is not UTF-8 encoded", input_path);
-        }
-    }
-}
-
-enum Void {}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn void(void: Void) {
-    if true {
-        match void {
-        }
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn mcarton_sees_all() {
-    panic!("meh");
-    panic!("möh");
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn try() -> Result<i32, &'static str> {
-    match 5 {
-        5 => Ok(5),
-        _ => return Err("bla"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn try_again() -> Result<i32, &'static str> {
-    let _ = try!(Ok(42));
-    let _ = try!(Ok(43));
-    let _ = try!(Ok(44));
-    let _ = try!(Ok(45));
-    let _ = try!(Ok(46));
-    let _ = try!(Ok(47));
-    let _ = try!(Ok(48));
-    let _ = try!(Ok(49));
-    match 5 {
-        5 => Ok(5),
-        _ => return Err("bla"),
-    }
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn early() -> Result<i32, &'static str> {
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-    return Ok(5);
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn early_ret() -> i32 {
-    let a = if true { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    let a = if a < 99 { 42 } else { return 0; };
-    match 5 {
-        5 => 5,
-        _ => return 6,
-    }
-}
diff --git a/tests/ui/cyclomatic_complexity.stderr b/tests/ui/cyclomatic_complexity.stderr
deleted file mode 100644 (file)
index 4367676..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-error: the function has a cyclomatic complexity of 28
-  --> $DIR/cyclomatic_complexity.rs:7:1
-   |
-7  | / fn main() {
-8  | |     if true {
-9  | |         println!("a");
-10 | |     }
-...  |
-88 | |     }
-89 | | }
-   | |_^
-   |
-   = note: `-D cyclomatic-complexity` implied by `-D warnings`
-   = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 7
-   --> $DIR/cyclomatic_complexity.rs:92:1
-    |
-92  | / fn kaboom() {
-93  | |     let n = 0;
-94  | |     'a: for i in 0..20 {
-95  | |         'b: for j in i..20 {
-...   |
-110 | |     }
-111 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 1
-   --> $DIR/cyclomatic_complexity.rs:138:1
-    |
-138 | / fn lots_of_short_circuits() -> bool {
-139 | |     true && false && true && false && true && false && true
-140 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 1
-   --> $DIR/cyclomatic_complexity.rs:143:1
-    |
-143 | / fn lots_of_short_circuits2() -> bool {
-144 | |     true || false || true || false || true || false || true
-145 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:148:1
-    |
-148 | / fn baa() {
-149 | |     let x = || match 99 {
-150 | |         0 => 0,
-151 | |         1 => 1,
-...   |
-162 | |     }
-163 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:149:13
-    |
-149 |       let x = || match 99 {
-    |  _____________^
-150 | |         0 => 0,
-151 | |         1 => 1,
-152 | |         2 => 2,
-...   |
-156 | |         _ => 42,
-157 | |     };
-    | |_____^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:166:1
-    |
-166 | / fn bar() {
-167 | |     match 99 {
-168 | |         0 => println!("hi"),
-169 | |         _ => println!("bye"),
-170 | |     }
-171 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:185:1
-    |
-185 | / fn barr() {
-186 | |     match 99 {
-187 | |         0 => println!("hi"),
-188 | |         1 => println!("bla"),
-...   |
-191 | |     }
-192 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 3
-   --> $DIR/cyclomatic_complexity.rs:195:1
-    |
-195 | / fn barr2() {
-196 | |     match 99 {
-197 | |         0 => println!("hi"),
-198 | |         1 => println!("bla"),
-...   |
-207 | |     }
-208 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:211:1
-    |
-211 | / fn barrr() {
-212 | |     match 99 {
-213 | |         0 => println!("hi"),
-214 | |         1 => panic!("bla"),
-...   |
-217 | |     }
-218 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 3
-   --> $DIR/cyclomatic_complexity.rs:221:1
-    |
-221 | / fn barrr2() {
-222 | |     match 99 {
-223 | |         0 => println!("hi"),
-224 | |         1 => panic!("bla"),
-...   |
-233 | |     }
-234 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:237:1
-    |
-237 | / fn barrrr() {
-238 | |     match 99 {
-239 | |         0 => println!("hi"),
-240 | |         1 => println!("bla"),
-...   |
-243 | |     }
-244 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 3
-   --> $DIR/cyclomatic_complexity.rs:247:1
-    |
-247 | / fn barrrr2() {
-248 | |     match 99 {
-249 | |         0 => println!("hi"),
-250 | |         1 => println!("bla"),
-...   |
-259 | |     }
-260 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 2
-   --> $DIR/cyclomatic_complexity.rs:263:1
-    |
-263 | / fn cake() {
-264 | |     if 4 == 5 {
-265 | |         println!("yea");
-266 | |     } else {
-...   |
-269 | |     println!("whee");
-270 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 4
-   --> $DIR/cyclomatic_complexity.rs:274:1
-    |
-274 | / pub fn read_file(input_path: &str) -> String {
-275 | |     use std::fs::File;
-276 | |     use std::io::{Read, Write};
-277 | |     use std::path::Path;
-...   |
-299 | |     }
-300 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 1
-   --> $DIR/cyclomatic_complexity.rs:305:1
-    |
-305 | / fn void(void: Void) {
-306 | |     if true {
-307 | |         match void {
-308 | |         }
-309 | |     }
-310 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 1
-   --> $DIR/cyclomatic_complexity.rs:319:1
-    |
-319 | / fn try() -> Result<i32, &'static str> {
-320 | |     match 5 {
-321 | |         5 => Ok(5),
-322 | |         _ => return Err("bla"),
-323 | |     }
-324 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 1
-   --> $DIR/cyclomatic_complexity.rs:327:1
-    |
-327 | / fn try_again() -> Result<i32, &'static str> {
-328 | |     let _ = try!(Ok(42));
-329 | |     let _ = try!(Ok(43));
-330 | |     let _ = try!(Ok(44));
-...   |
-339 | |     }
-340 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 1
-   --> $DIR/cyclomatic_complexity.rs:343:1
-    |
-343 | / fn early() -> Result<i32, &'static str> {
-344 | |     return Ok(5);
-345 | |     return Ok(5);
-346 | |     return Ok(5);
-...   |
-352 | |     return Ok(5);
-353 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: the function has a cyclomatic complexity of 8
-   --> $DIR/cyclomatic_complexity.rs:356:1
-    |
-356 | / fn early_ret() -> i32 {
-357 | |     let a = if true { 42 } else { return 0; };
-358 | |     let a = if a < 99 { 42 } else { return 0; };
-359 | |     let a = if a < 99 { 42 } else { return 0; };
-...   |
-372 | |     }
-373 | | }
-    | |_^
-    |
-    = help: you could split it up into multiple smaller functions
-
-error: aborting due to 20 previous errors
-
diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs
deleted file mode 100644 (file)
index 50b19f9..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(tool_attributes)]
-
-#![warn(cyclomatic_complexity)]
-#![warn(unused)]
-
-fn main() {
-    kaboom();
-}
-
-#[clippy::cyclomatic_complexity = "0"]
-fn kaboom() {
-    if 42 == 43 {
-        panic!();
-    } else if "cake" == "lie" {
-        println!("what?");
-    }
-}
diff --git a/tests/ui/cyclomatic_complexity_attr_used.stderr b/tests/ui/cyclomatic_complexity_attr_used.stderr
deleted file mode 100644 (file)
index e671b34..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error: the function has a cyclomatic complexity of 3
-  --> $DIR/cyclomatic_complexity_attr_used.rs:11:1
-   |
-11 | / fn kaboom() {
-12 | |     if 42 == 43 {
-13 | |         panic!();
-14 | |     } else if "cake" == "lie" {
-15 | |         println!("what?");
-16 | |     }
-17 | | }
-   | |_^
-   |
-   = note: `-D cyclomatic-complexity` implied by `-D warnings`
-   = help: you could split it up into multiple smaller functions
-
-error: aborting due to previous error
-
diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs
new file mode 100644 (file)
index 0000000..d2df7fb
--- /dev/null
@@ -0,0 +1,23 @@
+#![warn(clippy::dbg_macro)]
+
+fn foo(n: u32) -> u32 {
+    if let Some(n) = dbg!(n.checked_sub(4)) {
+        n
+    } else {
+        n
+    }
+}
+
+fn factorial(n: u32) -> u32 {
+    if dbg!(n <= 1) {
+        dbg!(1)
+    } else {
+        dbg!(n * factorial(n - 1))
+    }
+}
+
+fn main() {
+    dbg!(42);
+    dbg!(dbg!(dbg!(42)));
+    foo(3) + dbg!(factorial(4));
+}
diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr
new file mode 100644 (file)
index 0000000..43a6018
--- /dev/null
@@ -0,0 +1,74 @@
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:4:22
+   |
+LL |     if let Some(n) = dbg!(n.checked_sub(4)) {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::dbg-macro` implied by `-D warnings`
+help: ensure to avoid having uses of it in version control
+   |
+LL |     if let Some(n) = n.checked_sub(4) {
+   |                      ^^^^^^^^^^^^^^^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:12:8
+   |
+LL |     if dbg!(n <= 1) {
+   |        ^^^^^^^^^^^^
+help: ensure to avoid having uses of it in version control
+   |
+LL |     if n <= 1 {
+   |        ^^^^^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:13:9
+   |
+LL |         dbg!(1)
+   |         ^^^^^^^
+help: ensure to avoid having uses of it in version control
+   |
+LL |         1
+   |
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:15:9
+   |
+LL |         dbg!(n * factorial(n - 1))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ensure to avoid having uses of it in version control
+   |
+LL |         n * factorial(n - 1)
+   |
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:20:5
+   |
+LL |     dbg!(42);
+   |     ^^^^^^^^
+help: ensure to avoid having uses of it in version control
+   |
+LL |     42;
+   |     ^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:21:5
+   |
+LL |     dbg!(dbg!(dbg!(42)));
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: ensure to avoid having uses of it in version control
+   |
+LL |     dbg!(dbg!(42));
+   |     ^^^^^^^^^^^^^^
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:22:14
+   |
+LL |     foo(3) + dbg!(factorial(4));
+   |              ^^^^^^^^^^^^^^^^^^
+help: ensure to avoid having uses of it in version control
+   |
+LL |     foo(3) + factorial(4);
+   |              ^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
index 5463b8957f325cef1bbf7cdffbc9a2b35ea6a095..d841f16757a54d8d9d214164c1e23b4ec547dbb9 100644 (file)
@@ -1,18 +1,16 @@
-
-
-
-#[warn(decimal_literal_representation)]
+#[warn(clippy::decimal_literal_representation)]
 #[allow(unused_variables)]
+#[rustfmt::skip]
 fn main() {
-    let good = (        // Hex:
-        127,            // 0x7F
-        256,            // 0x100
-        511,            // 0x1FF
-        2048,           // 0x800
-        4090,           // 0xFFA
-        16_371,         // 0x3FF3
-        61_683,         // 0xF0F3
-        2_131_750_925,  // 0x7F0F_F00D
+    let good = (       // Hex:
+        127,           // 0x7F
+        256,           // 0x100
+        511,           // 0x1FF
+        2048,          // 0x800
+        4090,          // 0xFFA
+        16_371,        // 0x3FF3
+        61_683,        // 0xF0F3
+        2_131_750_925, // 0x7F0F_F00D
     );
     let bad = (        // Hex:
         32_773,        // 0x8005
index baed3c41180ce0758c8b4deba5626fbc0caaa603..3a535def1971290ebddf2ca5f6a50c2f83d0471d 100644 (file)
@@ -1,33 +1,33 @@
 error: integer literal has a better hexadecimal representation
-  --> $DIR/decimal_literal_representation.rs:18:9
+  --> $DIR/decimal_literal_representation.rs:16:9
    |
-18 |         32_773,        // 0x8005
+LL |         32_773,        // 0x8005
    |         ^^^^^^ help: consider: `0x8005`
    |
-   = note: `-D decimal-literal-representation` implied by `-D warnings`
+   = note: `-D clippy::decimal-literal-representation` implied by `-D warnings`
 
 error: integer literal has a better hexadecimal representation
-  --> $DIR/decimal_literal_representation.rs:19:9
+  --> $DIR/decimal_literal_representation.rs:17:9
    |
-19 |         65_280,        // 0xFF00
+LL |         65_280,        // 0xFF00
    |         ^^^^^^ help: consider: `0xFF00`
 
 error: integer literal has a better hexadecimal representation
-  --> $DIR/decimal_literal_representation.rs:20:9
+  --> $DIR/decimal_literal_representation.rs:18:9
    |
-20 |         2_131_750_927, // 0x7F0F_F00F
+LL |         2_131_750_927, // 0x7F0F_F00F
    |         ^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F`
 
 error: integer literal has a better hexadecimal representation
-  --> $DIR/decimal_literal_representation.rs:21:9
+  --> $DIR/decimal_literal_representation.rs:19:9
    |
-21 |         2_147_483_647, // 0x7FFF_FFFF
+LL |         2_147_483_647, // 0x7FFF_FFFF
    |         ^^^^^^^^^^^^^ help: consider: `0x7FFF_FFFF`
 
 error: integer literal has a better hexadecimal representation
-  --> $DIR/decimal_literal_representation.rs:22:9
+  --> $DIR/decimal_literal_representation.rs:20:9
    |
-22 |         4_042_322_160, // 0xF0F0_F0F0
+LL |         4_042_322_160, // 0xF0F0_F0F0
    |         ^^^^^^^^^^^^^ help: consider: `0xF0F0_F0F0`
 
 error: aborting due to 5 previous errors
index 675e64246fa909b43339da9424780205812b5400..2f1490a70369e267a340f726fd9227cd3d9fe6b6 100644 (file)
@@ -1,8 +1,8 @@
-#![warn(default_trait_access)]
+#![warn(clippy::default_trait_access)]
 
+use std::default;
 use std::default::Default as D2;
 use std::string;
-use std::default;
 
 fn main() {
     let s1: String = Default::default();
@@ -41,8 +41,10 @@ fn main() {
 
     let s18 = TupleStructDerivedDefault::default();
 
+    let s19 = <DerivedDefault as Default>::default();
+
     println!(
-        "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
+        "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}], [{:?}]",
         s1,
         s2,
         s3,
@@ -61,6 +63,7 @@ fn main() {
         s16,
         s17,
         s18,
+        s19,
     );
 }
 
index 8bb4731035aecd5496af36bbd5af1ce0d276c88f..1f115aecca1b5a9b17c86243aa48ff69d000c63f 100644 (file)
@@ -1,51 +1,51 @@
 error: Calling std::string::String::default() is more clear than this expression
- --> $DIR/default_trait_access.rs:8:22
-  |
-8 |     let s1: String = Default::default();
-  |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
-  |
-  = note: `-D default-trait-access` implied by `-D warnings`
 --> $DIR/default_trait_access.rs:8:22
+   |
+LL |     let s1: String = Default::default();
+   |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
+   |
+   = note: `-D clippy::default-trait-access` implied by `-D warnings`
 
 error: Calling std::string::String::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:12:22
    |
-12 |     let s3: String = D2::default();
+LL |     let s3: String = D2::default();
    |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: Calling std::string::String::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:14:22
    |
-14 |     let s4: String = std::default::Default::default();
+LL |     let s4: String = std::default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: Calling std::string::String::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:18:22
    |
-18 |     let s6: String = default::Default::default();
+LL |     let s6: String = default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: Calling GenericDerivedDefault<std::string::String>::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:28:46
    |
-28 |     let s11: GenericDerivedDefault<String> = Default::default();
+LL |     let s11: GenericDerivedDefault<String> = Default::default();
    |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault<std::string::String>::default()`
 
 error: Calling TupleDerivedDefault::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:34:36
    |
-34 |     let s14: TupleDerivedDefault = Default::default();
+LL |     let s14: TupleDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
 
 error: Calling ArrayDerivedDefault::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:36:36
    |
-36 |     let s15: ArrayDerivedDefault = Default::default();
+LL |     let s15: ArrayDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
 
 error: Calling TupleStructDerivedDefault::default() is more clear than this expression
   --> $DIR/default_trait_access.rs:40:42
    |
-40 |     let s17: TupleStructDerivedDefault = Default::default();
+LL |     let s17: TupleStructDerivedDefault = Default::default();
    |                                          ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
 
 error: aborting due to 8 previous errors
index f456c4172237b59df0711de46ff03a9d8bb7f556..2e5c5b7ead12c1e2fd81b2816473939feb5b508f 100644 (file)
@@ -1,14 +1,7 @@
-
-
-
 #[warn(str_to_string)]
-
 #[warn(string_to_string)]
-
 #[warn(unstable_as_slice)]
-
 #[warn(unstable_as_mut_slice)]
-
 #[warn(misaligned_transmute)]
 
 fn main() {}
index 6bbc0aebf9c9bd07c860c62a2c23dc2ba0647a01..ea809472cb286973a6e1004d35a21a513bcad19e 100644 (file)
@@ -1,34 +1,40 @@
 error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
--> $DIR/deprecated.rs:4:8
-  |
-4 | #[warn(str_to_string)]
-  |        ^^^^^^^^^^^^^
-  |
-  = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 --> $DIR/deprecated.rs:1:8
+   |
+LL | #[warn(str_to_string)]
+   |        ^^^^^^^^^^^^^
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon`
--> $DIR/deprecated.rs:6:8
-  |
-6 | #[warn(string_to_string)]
-  |        ^^^^^^^^^^^^^^^^
 --> $DIR/deprecated.rs:2:8
+   |
+LL | #[warn(string_to_string)]
+   |        ^^^^^^^^^^^^^^^^
 
 error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
--> $DIR/deprecated.rs:8:8
-  |
-8 | #[warn(unstable_as_slice)]
-  |        ^^^^^^^^^^^^^^^^^
 --> $DIR/deprecated.rs:3:8
+   |
+LL | #[warn(unstable_as_slice)]
+   |        ^^^^^^^^^^^^^^^^^
 
 error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
-  --> $DIR/deprecated.rs:10:8
+  --> $DIR/deprecated.rs:4:8
    |
-10 | #[warn(unstable_as_mut_slice)]
+LL | #[warn(unstable_as_mut_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
-  --> $DIR/deprecated.rs:12:8
+  --> $DIR/deprecated.rs:5:8
    |
-12 | #[warn(misaligned_transmute)]
+LL | #[warn(misaligned_transmute)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
+  --> $DIR/deprecated.rs:1:8
+   |
+LL | #[warn(str_to_string)]
+   |        ^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed
new file mode 100644 (file)
index 0000000..9e5b51d
--- /dev/null
@@ -0,0 +1,39 @@
+// run-rustfix
+
+fn get_number() -> usize {
+    10
+}
+
+fn get_reference(n: &usize) -> &usize {
+    n
+}
+
+#[allow(clippy::many_single_char_names, clippy::double_parens)]
+#[allow(unused_variables, unused_parens)]
+#[warn(clippy::deref_addrof)]
+fn main() {
+    let a = 10;
+    let aref = &a;
+
+    let b = a;
+
+    let b = get_number();
+
+    let b = *get_reference(&a);
+
+    let bytes: Vec<usize> = vec![1, 2, 3, 4];
+    let b = bytes[1..2][0];
+
+    //This produces a suggestion of 'let b = (a);' which
+    //will trigger the 'unused_parens' lint
+    let b = (a);
+
+    let b = a;
+
+    #[rustfmt::skip]
+    let b = a;
+
+    let b = &a;
+
+    let b = *aref;
+}
diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs
new file mode 100644 (file)
index 0000000..5641a73
--- /dev/null
@@ -0,0 +1,39 @@
+// run-rustfix
+
+fn get_number() -> usize {
+    10
+}
+
+fn get_reference(n: &usize) -> &usize {
+    n
+}
+
+#[allow(clippy::many_single_char_names, clippy::double_parens)]
+#[allow(unused_variables, unused_parens)]
+#[warn(clippy::deref_addrof)]
+fn main() {
+    let a = 10;
+    let aref = &a;
+
+    let b = *&a;
+
+    let b = *&get_number();
+
+    let b = *get_reference(&a);
+
+    let bytes: Vec<usize> = vec![1, 2, 3, 4];
+    let b = *&bytes[1..2][0];
+
+    //This produces a suggestion of 'let b = (a);' which
+    //will trigger the 'unused_parens' lint
+    let b = *&(a);
+
+    let b = *(&a);
+
+    #[rustfmt::skip]
+    let b = *((&a));
+
+    let b = *&&a;
+
+    let b = **&aref;
+}
diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr
new file mode 100644 (file)
index 0000000..bc51719
--- /dev/null
@@ -0,0 +1,52 @@
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:18:13
+   |
+LL |     let b = *&a;
+   |             ^^^ help: try this: `a`
+   |
+   = note: `-D clippy::deref-addrof` implied by `-D warnings`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:20:13
+   |
+LL |     let b = *&get_number();
+   |             ^^^^^^^^^^^^^^ help: try this: `get_number()`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:25:13
+   |
+LL |     let b = *&bytes[1..2][0];
+   |             ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:29:13
+   |
+LL |     let b = *&(a);
+   |             ^^^^^ help: try this: `(a)`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:31:13
+   |
+LL |     let b = *(&a);
+   |             ^^^^^ help: try this: `a`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:34:13
+   |
+LL |     let b = *((&a));
+   |             ^^^^^^^ help: try this: `a`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:36:13
+   |
+LL |     let b = *&&a;
+   |             ^^^^ help: try this: `&a`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof.rs:38:14
+   |
+LL |     let b = **&aref;
+   |              ^^^^^^ help: try this: `aref`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/deref_addrof_double_trigger.rs b/tests/ui/deref_addrof_double_trigger.rs
new file mode 100644 (file)
index 0000000..e19af5b
--- /dev/null
@@ -0,0 +1,21 @@
+#[warn(clippy::deref_addrof)]
+#[allow(unused_variables)]
+fn main() {
+    let a = 10;
+
+    //This produces a suggestion of 'let b = *&a;' which
+    //will trigger the 'clippy::deref_addrof' lint again
+    let b = **&&a;
+
+    {
+        let mut x = 10;
+        let y = *&mut x;
+    }
+
+    {
+        //This produces a suggestion of 'let y = *&mut x' which
+        //will trigger the 'clippy::deref_addrof' lint again
+        let mut x = 10;
+        let y = **&mut &mut x;
+    }
+}
diff --git a/tests/ui/deref_addrof_double_trigger.stderr b/tests/ui/deref_addrof_double_trigger.stderr
new file mode 100644 (file)
index 0000000..89284e1
--- /dev/null
@@ -0,0 +1,22 @@
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof_double_trigger.rs:8:14
+   |
+LL |     let b = **&&a;
+   |              ^^^^ help: try this: `&a`
+   |
+   = note: `-D clippy::deref-addrof` implied by `-D warnings`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof_double_trigger.rs:12:17
+   |
+LL |         let y = *&mut x;
+   |                 ^^^^^^^ help: try this: `x`
+
+error: immediately dereferencing a reference
+  --> $DIR/deref_addrof_double_trigger.rs:19:18
+   |
+LL |         let y = **&mut &mut x;
+   |                  ^^^^^^^^^^^^ help: try this: `&mut x`
+
+error: aborting due to 3 previous errors
+
index f43b8c382a4afdfb8f5214c25dbcc870f81e2d5e..b7a672cd80aaafdc578ccc0f8d48cf5aefb85fab 100644 (file)
@@ -1,9 +1,6 @@
-
-
 #![feature(untagged_unions)]
-
 #![allow(dead_code)]
-#![warn(expl_impl_clone_on_copy)]
+#![warn(clippy::expl_impl_clone_on_copy)]
 
 use std::hash::{Hash, Hasher};
 
 struct Foo;
 
 impl PartialEq<u64> for Foo {
-    fn eq(&self, _: &u64) -> bool { true }
+    fn eq(&self, _: &u64) -> bool {
+        true
+    }
 }
 
 #[derive(Hash)]
 struct Bar;
 
 impl PartialEq for Bar {
-    fn eq(&self, _: &Bar) -> bool { true }
+    fn eq(&self, _: &Bar) -> bool {
+        true
+    }
 }
 
 #[derive(Hash)]
 struct Baz;
 
 impl PartialEq<Baz> for Baz {
-    fn eq(&self, _: &Baz) -> bool { true }
+    fn eq(&self, _: &Baz) -> bool {
+        true
+    }
 }
 
 #[derive(PartialEq)]
@@ -39,7 +42,9 @@ fn hash<H: Hasher>(&self, _: &mut H) {}
 struct Qux;
 
 impl Clone for Qux {
-    fn clone(&self) -> Self { Qux }
+    fn clone(&self) -> Self {
+        Qux
+    }
 }
 
 // looks like unions don't support deriving Clone for now
@@ -50,9 +55,7 @@ union Union {
 
 impl Clone for Union {
     fn clone(&self) -> Self {
-        Union {
-            a: 42,
-        }
+        Union { a: 42 }
     }
 }
 
@@ -63,7 +66,9 @@ struct Lt<'a> {
 }
 
 impl<'a> Clone for Lt<'a> {
-    fn clone(&self) -> Self { unimplemented!() }
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
 }
 
 // Ok, `Clone` cannot be derived because of the big array
@@ -73,7 +78,9 @@ struct BigArray {
 }
 
 impl Clone for BigArray {
-    fn clone(&self) -> Self { unimplemented!() }
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
 }
 
 // Ok, function pointers are not always Clone
@@ -83,7 +90,9 @@ struct FnPtr {
 }
 
 impl Clone for FnPtr {
-    fn clone(&self) -> Self { unimplemented!() }
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
 }
 
 // Ok, generics
@@ -93,7 +102,9 @@ struct Generic<T> {
 }
 
 impl<T> Clone for Generic<T> {
-    fn clone(&self) -> Self { unimplemented!() }
+    fn clone(&self) -> Self {
+        unimplemented!()
+    }
 }
 
 fn main() {}
index cbe3fe1029dc959161017d0f5e3ac3fb97e2ba4d..fc87c7d159608172ddcb3267492647eff572784b 100644 (file)
 error: you are deriving `Hash` but have implemented `PartialEq` explicitly
-  --> $DIR/derive.rs:17:10
+  --> $DIR/derive.rs:16:10
    |
-17 | #[derive(Hash)]
+LL | #[derive(Hash)]
    |          ^^^^
    |
-   = note: #[deny(derive_hash_xor_eq)] on by default
+   = note: #[deny(clippy::derive_hash_xor_eq)] on by default
 note: `PartialEq` implemented here
-  --> $DIR/derive.rs:20:1
+  --> $DIR/derive.rs:19:1
    |
-20 | / impl PartialEq for Bar {
-21 | |     fn eq(&self, _: &Bar) -> bool { true }
-22 | | }
+LL | / impl PartialEq for Bar {
+LL | |     fn eq(&self, _: &Bar) -> bool {
+LL | |         true
+LL | |     }
+LL | | }
    | |_^
 
 error: you are deriving `Hash` but have implemented `PartialEq` explicitly
-  --> $DIR/derive.rs:24:10
+  --> $DIR/derive.rs:25:10
    |
-24 | #[derive(Hash)]
+LL | #[derive(Hash)]
    |          ^^^^
    |
 note: `PartialEq` implemented here
-  --> $DIR/derive.rs:27:1
+  --> $DIR/derive.rs:28:1
    |
-27 | / impl PartialEq<Baz> for Baz {
-28 | |     fn eq(&self, _: &Baz) -> bool { true }
-29 | | }
+LL | / impl PartialEq<Baz> for Baz {
+LL | |     fn eq(&self, _: &Baz) -> bool {
+LL | |         true
+LL | |     }
+LL | | }
    | |_^
 
 error: you are implementing `Hash` explicitly but have derived `PartialEq`
-  --> $DIR/derive.rs:34:1
+  --> $DIR/derive.rs:37:1
    |
-34 | / impl Hash for Bah {
-35 | |     fn hash<H: Hasher>(&self, _: &mut H) {}
-36 | | }
+LL | / impl Hash for Bah {
+LL | |     fn hash<H: Hasher>(&self, _: &mut H) {}
+LL | | }
    | |_^
    |
 note: `PartialEq` implemented here
-  --> $DIR/derive.rs:31:10
+  --> $DIR/derive.rs:34:10
    |
-31 | #[derive(PartialEq)]
+LL | #[derive(PartialEq)]
    |          ^^^^^^^^^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:41:1
+  --> $DIR/derive.rs:44:1
    |
-41 | / impl Clone for Qux {
-42 | |     fn clone(&self) -> Self { Qux }
-43 | | }
+LL | / impl Clone for Qux {
+LL | |     fn clone(&self) -> Self {
+LL | |         Qux
+LL | |     }
+LL | | }
    | |_^
    |
-   = note: `-D expl-impl-clone-on-copy` implied by `-D warnings`
+   = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings`
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:41:1
+  --> $DIR/derive.rs:44:1
    |
-41 | / impl Clone for Qux {
-42 | |     fn clone(&self) -> Self { Qux }
-43 | | }
+LL | / impl Clone for Qux {
+LL | |     fn clone(&self) -> Self {
+LL | |         Qux
+LL | |     }
+LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:65:1
+  --> $DIR/derive.rs:68:1
    |
-65 | / impl<'a> Clone for Lt<'a> {
-66 | |     fn clone(&self) -> Self { unimplemented!() }
-67 | | }
+LL | / impl<'a> Clone for Lt<'a> {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:65:1
+  --> $DIR/derive.rs:68:1
    |
-65 | / impl<'a> Clone for Lt<'a> {
-66 | |     fn clone(&self) -> Self { unimplemented!() }
-67 | | }
+LL | / impl<'a> Clone for Lt<'a> {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:75:1
+  --> $DIR/derive.rs:80:1
    |
-75 | / impl Clone for BigArray {
-76 | |     fn clone(&self) -> Self { unimplemented!() }
-77 | | }
+LL | / impl Clone for BigArray {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:75:1
+  --> $DIR/derive.rs:80:1
    |
-75 | / impl Clone for BigArray {
-76 | |     fn clone(&self) -> Self { unimplemented!() }
-77 | | }
+LL | / impl Clone for BigArray {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
    | |_^
 
 error: you are implementing `Clone` explicitly on a `Copy` type
-  --> $DIR/derive.rs:85:1
+  --> $DIR/derive.rs:92:1
    |
-85 | / impl Clone for FnPtr {
-86 | |     fn clone(&self) -> Self { unimplemented!() }
-87 | | }
+LL | / impl Clone for FnPtr {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
    | |_^
    |
 note: consider deriving `Clone` or removing `Copy`
-  --> $DIR/derive.rs:85:1
+  --> $DIR/derive.rs:92:1
    |
-85 | / impl Clone for FnPtr {
-86 | |     fn clone(&self) -> Self { unimplemented!() }
-87 | | }
+LL | / impl Clone for FnPtr {
+LL | |     fn clone(&self) -> Self {
+LL | |         unimplemented!()
+LL | |     }
+LL | | }
    | |_^
 
 error: aborting due to 7 previous errors
index b89a2f1bcaffae2c1e9f599ae3392bd6bccfc648..746afa475039e99c5967bb27615f1b3b09531638 100644 (file)
@@ -1,18 +1,21 @@
 #![feature(never_type)]
+#![warn(clippy::diverging_sub_expression)]
+#![allow(clippy::match_same_arms, clippy::logic_bug)]
 
-#![warn(diverging_sub_expression)]
-#![allow(match_same_arms, logic_bug)]
-
-#[allow(empty_loop)]
-fn diverge() -> ! { loop {} }
+#[allow(clippy::empty_loop)]
+fn diverge() -> ! {
+    loop {}
+}
 
 struct A;
 
 impl A {
-    fn foo(&self) -> ! { diverge() }
+    fn foo(&self) -> ! {
+        diverge()
+    }
 }
 
-#[allow(unused_variables, unnecessary_operation, short_circuit_statement)]
+#[allow(unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
 fn main() {
     let b = true;
     b || diverge();
index 0d7b1ca6fd66ca3488f08eba0daaae89e6cdcffb..70ff3cdd0462f5eb176adb5e493f1a61bef31ab8 100644 (file)
@@ -1,39 +1,39 @@
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:18:10
+  --> $DIR/diverging_sub_expression.rs:21:10
    |
-18 |     b || diverge();
+LL |     b || diverge();
    |          ^^^^^^^^^
    |
-   = note: `-D diverging-sub-expression` implied by `-D warnings`
+   = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:19:10
+  --> $DIR/diverging_sub_expression.rs:22:10
    |
-19 |     b || A.foo();
+LL |     b || A.foo();
    |          ^^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:28:26
+  --> $DIR/diverging_sub_expression.rs:31:26
    |
-28 |             6 => true || return,
+LL |             6 => true || return,
    |                          ^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:29:26
+  --> $DIR/diverging_sub_expression.rs:32:26
    |
-29 |             7 => true || continue,
+LL |             7 => true || continue,
    |                          ^^^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:32:26
+  --> $DIR/diverging_sub_expression.rs:35:26
    |
-32 |             3 => true || diverge(),
+LL |             3 => true || diverge(),
    |                          ^^^^^^^^^
 
 error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:37:26
+  --> $DIR/diverging_sub_expression.rs:40:26
    |
-37 |             _ => true || break,
+LL |             _ => true || break,
    |                          ^^^^^
 
 error: aborting due to 6 previous errors
index 1318ed78717da7d072ba711da6c88d2b59d2c417..5af79f9c58ed7cc3f56ae79332f01280298c86b0 100644 (file)
@@ -1,9 +1,6 @@
-#![feature(alloc)]
 #![feature(associated_type_defaults)]
-
-
-#![warn(linkedlist)]
-#![allow(dead_code, needless_pass_by_value)]
+#![warn(clippy::linkedlist)]
+#![allow(dead_code, clippy::needless_pass_by_value)]
 
 extern crate alloc;
 use alloc::collections::linked_list::LinkedList;
 trait Foo {
     type Baz = LinkedList<u8>;
     fn foo(LinkedList<u8>);
-    const BAR : Option<LinkedList<u8>>;
+    const BAR: Option<LinkedList<u8>>;
 }
 
-// ok, we don’t want to warn for implementations, see #605
+// Ok, we don’t want to warn for implementations; see issue #605.
 impl Foo for LinkedList<u8> {
     fn foo(_: LinkedList<u8>) {}
-    const BAR : Option<LinkedList<u8>> = None;
+    const BAR: Option<LinkedList<u8>> = None;
 }
 
 struct Bar;
@@ -37,7 +34,7 @@ pub fn test_local_not_linted() {
     let _: LinkedList<u8>;
 }
 
-fn main(){
+fn main() {
     test(LinkedList::new());
     test_local_not_linted();
 }
index de0422e17eddacff89b120df1e45d772680ad042..e4712e5d07f86d45526459e34545329d100a5f25 100644 (file)
@@ -1,48 +1,48 @@
 error: I see you're using a LinkedList! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:12:16
+  --> $DIR/dlist.rs:9:16
    |
-12 |     type Baz = LinkedList<u8>;
+LL |     type Baz = LinkedList<u8>;
    |                ^^^^^^^^^^^^^^
    |
-   = note: `-D linkedlist` implied by `-D warnings`
+   = note: `-D clippy::linkedlist` implied by `-D warnings`
    = help: a VecDeque might work
 
 error: I see you're using a LinkedList! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:13:12
+  --> $DIR/dlist.rs:10:12
    |
-13 |     fn foo(LinkedList<u8>);
+LL |     fn foo(LinkedList<u8>);
    |            ^^^^^^^^^^^^^^
    |
    = help: a VecDeque might work
 
 error: I see you're using a LinkedList! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:14:24
+  --> $DIR/dlist.rs:11:23
    |
-14 |     const BAR : Option<LinkedList<u8>>;
-   |                        ^^^^^^^^^^^^^^
+LL |     const BAR: Option<LinkedList<u8>>;
+   |                       ^^^^^^^^^^^^^^
    |
    = help: a VecDeque might work
 
 error: I see you're using a LinkedList! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:25:15
+  --> $DIR/dlist.rs:22:15
    |
-25 |     fn foo(_: LinkedList<u8>) {}
+LL |     fn foo(_: LinkedList<u8>) {}
    |               ^^^^^^^^^^^^^^
    |
    = help: a VecDeque might work
 
 error: I see you're using a LinkedList! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:28:39
+  --> $DIR/dlist.rs:25:39
    |
-28 | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
+LL | pub fn test(my_favourite_linked_list: LinkedList<u8>) {
    |                                       ^^^^^^^^^^^^^^
    |
    = help: a VecDeque might work
 
 error: I see you're using a LinkedList! Perhaps you meant some other data structure?
-  --> $DIR/dlist.rs:32:29
+  --> $DIR/dlist.rs:29:29
    |
-32 | pub fn test_ret() -> Option<LinkedList<u8>> {
+LL | pub fn test_ret() -> Option<LinkedList<u8>> {
    |                             ^^^^^^^^^^^^^^
    |
    = help: a VecDeque might work
index 45e25409b128b50513482155609160cf8b8b42d6..039ce5d9c423edc8fda2c442870111288873ae34 100644 (file)
@@ -1,12 +1,12 @@
-//! This file tests for the DOC_MARKDOWN lint
-
-
+//! This file tests for the `DOC_MARKDOWN` lint.
 
 #![allow(dead_code)]
-#![warn(doc_markdown)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
 
 /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-/// Markdown is _weird_. I mean _really weird_.  This \_ is ok. So is `_`. But not Foo::some_fun
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
 /// which should be reported only once despite being __doubly bad__.
 /// Here be ::a::global:path.
 /// That's not code ~NotInCodeBlock~.
@@ -50,7 +50,7 @@ fn test_units() {
 }
 
 /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
-/// See also [the issue tracker](https://github.com/rust-lang-nursery/rust-clippy/search?q=doc_markdown&type=Issues)
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
 /// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
 /// It can also be [inline_link2].
 ///
@@ -71,7 +71,7 @@ fn main() {
 }
 
 /// ## CamelCaseThing
-/// Talks about `CamelCaseThing`. Titles should be ignored, see issue #897.
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
 ///
 /// # CamelCaseThing
 ///
@@ -107,7 +107,7 @@ fn issue883() {
 fn multiline() {
 }
 
-/** E.g. serialization of an empty list: FooBar
+/** E.g., serialization of an empty list: FooBar
 ```
 That's in a code block: `PackedNode`
 ```
@@ -118,7 +118,7 @@ fn multiline() {
 fn issue1073() {
 }
 
-/** E.g. serialization of an empty list: FooBar
+/** E.g., serialization of an empty list: FooBar
 ```
 That's in a code block: PackedNode
 ```
@@ -129,7 +129,7 @@ fn issue1073() {
 fn issue1073_alt() {
 }
 
-/// Test more than three quotes:
+/// Tests more than three quotes:
 /// ````
 /// DoNotWarn
 /// ```
@@ -142,7 +142,7 @@ fn four_quotes() {
 /// See [NIST SP 800-56A, revision 2].
 ///
 /// [NIST SP 800-56A, revision 2]:
-///     https://github.com/rust-lang-nursery/rust-clippy/issues/902#issuecomment-261919419
+///     https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
 fn issue_902_comment() {}
 
 #[cfg_attr(feature = "a", doc = " ```")]
@@ -167,3 +167,14 @@ fn issue_1920() {}
 /// Not ok: http://www.unicode.org/
 /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
 fn issue_1832() {}
+
+/// Ok: CamelCase (It should not be surrounded by backticks)
+fn issue_2395() {}
+
+/// An iterator over mycrate::Collection's values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
index f38678e89aac234b8488534a00cc05f3ff97ea52..ae9bb394cb9ac726bcca6129a5e7bb1c3349741d 100644 (file)
-error: you should put `DOC_MARKDOWN` between ticks in the documentation
- --> $DIR/doc.rs:1:29
-  |
-1 | //! This file tests for the DOC_MARKDOWN lint
-  |                             ^^^^^^^^^^^^
-  |
-  = note: `-D doc-markdown` implied by `-D warnings`
-
 error: you should put `foo_bar` between ticks in the documentation
- --> $DIR/doc.rs:8:9
-  |
-8 | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-  |         ^^^^^^^
+  --> $DIR/doc.rs:8:9
+   |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+   |         ^^^^^^^
+   |
+   = note: `-D clippy::doc-markdown` implied by `-D warnings`
 
 error: you should put `foo::bar` between ticks in the documentation
- --> $DIR/doc.rs:8:51
-  |
-8 | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-  |                                                   ^^^^^^^^
 --> $DIR/doc.rs:8:51
+   |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+   |                                                   ^^^^^^^^
 
 error: you should put `Foo::some_fun` between ticks in the documentation
- --> $DIR/doc.rs:9:84
-  |
-9 | /// Markdown is _weird_. I mean _really weird_.  This /_ is ok. So is `_`. But not Foo::some_fun
-                                                                                     ^^^^^^^^^^^^^
+  --> $DIR/doc.rs:9:83
+   |
+LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
+   |                                                                                   ^^^^^^^^^^^^^
 
 error: you should put `a::global:path` between ticks in the documentation
   --> $DIR/doc.rs:11:15
    |
-11 | /// Here be ::a::global:path.
+LL | /// Here be ::a::global:path.
    |               ^^^^^^^^^^^^^^
 
 error: you should put `NotInCodeBlock` between ticks in the documentation
   --> $DIR/doc.rs:12:22
    |
-12 | /// That's not code ~NotInCodeBlock~.
+LL | /// That's not code ~NotInCodeBlock~.
    |                      ^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:13:5
    |
-13 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:27:5
    |
-27 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:34:5
    |
-34 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:48:5
    |
-48 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `link_with_underscores` between ticks in the documentation
   --> $DIR/doc.rs:52:22
    |
-52 | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
    |                      ^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `inline_link2` between ticks in the documentation
   --> $DIR/doc.rs:55:21
    |
-55 | /// It can also be [inline_link2].
+LL | /// It can also be [inline_link2].
    |                     ^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:65:5
    |
-65 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `CamelCaseThing` between ticks in the documentation
   --> $DIR/doc.rs:73:8
    |
-73 | /// ## CamelCaseThing
+LL | /// ## CamelCaseThing
    |        ^^^^^^^^^^^^^^
 
 error: you should put `CamelCaseThing` between ticks in the documentation
   --> $DIR/doc.rs:76:7
    |
-76 | /// # CamelCaseThing
+LL | /// # CamelCaseThing
    |       ^^^^^^^^^^^^^^
 
 error: you should put `CamelCaseThing` between ticks in the documentation
   --> $DIR/doc.rs:78:22
    |
-78 | /// Not a title #897 CamelCaseThing
+LL | /// Not a title #897 CamelCaseThing
    |                      ^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:79:5
    |
-79 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:86:5
    |
-86 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
   --> $DIR/doc.rs:99:5
    |
-99 | /// be_sure_we_got_to_the_end_of_it
+LL | /// be_sure_we_got_to_the_end_of_it
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `FooBar` between ticks in the documentation
-   --> $DIR/doc.rs:110:42
-    |
-110 | /** E.g. serialization of an empty list: FooBar
-    |                                          ^^^^^^
+  --> $DIR/doc.rs:110:43
+   |
+LL | /** E.g., serialization of an empty list: FooBar
+                                             ^^^^^^
 
 error: you should put `BarQuz` between ticks in the documentation
-   --> $DIR/doc.rs:115:5
-    |
-115 | And BarQuz too.
-    |     ^^^^^^
+  --> $DIR/doc.rs:115:5
+   |
+LL | And BarQuz too.
+   |     ^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-   --> $DIR/doc.rs:116:1
-    |
-116 | be_sure_we_got_to_the_end_of_it
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:116:1
+   |
+LL | be_sure_we_got_to_the_end_of_it
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `FooBar` between ticks in the documentation
-   --> $DIR/doc.rs:121:42
-    |
-121 | /** E.g. serialization of an empty list: FooBar
-    |                                          ^^^^^^
+  --> $DIR/doc.rs:121:43
+   |
+LL | /** E.g., serialization of an empty list: FooBar
+                                             ^^^^^^
 
 error: you should put `BarQuz` between ticks in the documentation
-   --> $DIR/doc.rs:126:5
-    |
-126 | And BarQuz too.
-    |     ^^^^^^
+  --> $DIR/doc.rs:126:5
+   |
+LL | And BarQuz too.
+   |     ^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-   --> $DIR/doc.rs:127:1
-    |
-127 | be_sure_we_got_to_the_end_of_it
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:127:1
+   |
+LL | be_sure_we_got_to_the_end_of_it
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
-   --> $DIR/doc.rs:138:5
-    |
-138 | /// be_sure_we_got_to_the_end_of_it
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:138:5
+   |
+LL | /// be_sure_we_got_to_the_end_of_it
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-   --> $DIR/doc.rs:165:13
-    |
-165 | /// Not ok: http://www.unicode.org
-    |             ^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:165:13
+   |
+LL | /// Not ok: http://www.unicode.org
+   |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-   --> $DIR/doc.rs:166:13
-    |
-166 | /// Not ok: https://www.unicode.org
-    |             ^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:166:13
+   |
+LL | /// Not ok: https://www.unicode.org
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-   --> $DIR/doc.rs:167:13
-    |
-167 | /// Not ok: http://www.unicode.org/
-    |             ^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:167:13
+   |
+LL | /// Not ok: http://www.unicode.org/
+   |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error: you should put bare URLs between `<`/`>` or make a proper Markdown link
-   --> $DIR/doc.rs:168:13
-    |
-168 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/doc.rs:168:13
+   |
+LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: you should put `mycrate::Collection` between ticks in the documentation
+  --> $DIR/doc.rs:174:22
+   |
+LL | /// An iterator over mycrate::Collection's values.
+   |                      ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 30 previous errors
 
diff --git a/tests/ui/double_comparison.fixed b/tests/ui/double_comparison.fixed
new file mode 100644 (file)
index 0000000..bb6cdaa
--- /dev/null
@@ -0,0 +1,30 @@
+// run-rustfix
+
+fn main() {
+    let x = 1;
+    let y = 2;
+    if x <= y {
+        // do something
+    }
+    if x <= y {
+        // do something
+    }
+    if x >= y {
+        // do something
+    }
+    if x >= y {
+        // do something
+    }
+    if x != y {
+        // do something
+    }
+    if x != y {
+        // do something
+    }
+    if x == y {
+        // do something
+    }
+    if x == y {
+        // do something
+    }
+}
index 2c8f116281bdd2e28a1ab01e65bbc84c2c277fe3..9a2a9068a28debe71293c7a2c19f013962f265c6 100644 (file)
@@ -1,3 +1,5 @@
+// run-rustfix
+
 fn main() {
     let x = 1;
     let y = 2;
index 73dd8d02877675d38f067991f5fe5e04752f49f3..5dcda7b3af4ac48187d6d84a3559793199f87593 100644 (file)
@@ -1,51 +1,51 @@
 error: This binary expression can be simplified
--> $DIR/double_comparison.rs:4:8
-  |
-4 |     if x == y || x < y {
-  |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
-  |
-  = note: `-D double-comparisons` implied by `-D warnings`
 --> $DIR/double_comparison.rs:6:8
+   |
+LL |     if x == y || x < y {
+   |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
+   |
+   = note: `-D clippy::double-comparisons` implied by `-D warnings`
 
 error: This binary expression can be simplified
--> $DIR/double_comparison.rs:7:8
-  |
-7 |     if x < y || x == y {
-  |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
 --> $DIR/double_comparison.rs:9:8
+   |
+LL |     if x < y || x == y {
+   |        ^^^^^^^^^^^^^^^ help: try: `x <= y`
 
 error: This binary expression can be simplified
-  --> $DIR/double_comparison.rs:10:8
+  --> $DIR/double_comparison.rs:12:8
    |
-10 |     if x == y || x > y {
+LL |     if x == y || x > y {
    |        ^^^^^^^^^^^^^^^ help: try: `x >= y`
 
 error: This binary expression can be simplified
-  --> $DIR/double_comparison.rs:13:8
+  --> $DIR/double_comparison.rs:15:8
    |
-13 |     if x > y || x == y {
+LL |     if x > y || x == y {
    |        ^^^^^^^^^^^^^^^ help: try: `x >= y`
 
 error: This binary expression can be simplified
-  --> $DIR/double_comparison.rs:16:8
+  --> $DIR/double_comparison.rs:18:8
    |
-16 |     if x < y || x > y {
+LL |     if x < y || x > y {
    |        ^^^^^^^^^^^^^^ help: try: `x != y`
 
 error: This binary expression can be simplified
-  --> $DIR/double_comparison.rs:19:8
+  --> $DIR/double_comparison.rs:21:8
    |
-19 |     if x > y || x < y {
+LL |     if x > y || x < y {
    |        ^^^^^^^^^^^^^^ help: try: `x != y`
 
 error: This binary expression can be simplified
-  --> $DIR/double_comparison.rs:22:8
+  --> $DIR/double_comparison.rs:24:8
    |
-22 |     if x <= y && x >= y {
+LL |     if x <= y && x >= y {
    |        ^^^^^^^^^^^^^^^^ help: try: `x == y`
 
 error: This binary expression can be simplified
-  --> $DIR/double_comparison.rs:25:8
+  --> $DIR/double_comparison.rs:27:8
    |
-25 |     if x >= y && x <= y {
+LL |     if x >= y && x <= y {
    |        ^^^^^^^^^^^^^^^^ help: try: `x == y`
 
 error: aborting due to 8 previous errors
index 641e334fd1657ba5ad2d66c3d0ae4a0b072a383e..d47dfcb5ba1eab1b8654a2c270700748923a4bee 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#[warn(double_neg)]
+#[warn(clippy::double_neg)]
 fn main() {
     let x = 1;
     -x;
index fd4da8820a24cefc6a79bfde38a4eb539e581ad9..d82ed05f0543dbf65a7fb5768c39ac7703561081 100644 (file)
@@ -1,10 +1,10 @@
 error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
--> $DIR/double_neg.rs:9:5
-  |
-9 |     --x;
-  |     ^^^
-  |
-  = note: `-D double-neg` implied by `-D warnings`
 --> $DIR/double_neg.rs:6:5
+   |
+LL |     --x;
+   |     ^^^
+   |
+   = note: `-D clippy::double-neg` implied by `-D warnings`
 
 error: aborting due to previous error
 
index 19d1773286757c35a8165df95cded41ac7f5d7f9..9c7590c7dd6324bc3afe069cf22bce3def645366 100644 (file)
@@ -1,8 +1,7 @@
-
-
-
-#![warn(double_parens)]
+#![warn(clippy::double_parens)]
 #![allow(dead_code)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
 
 fn dummy_fn<T>(_: T) {}
 
@@ -48,4 +47,10 @@ fn method_unit_ok(x: DummyStruct) {
     x.dummy_method(());
 }
 
+// Issue #3206
+fn inside_macro() {
+    assert_eq!((1, 2), (1, 2), "Error");
+    assert_eq!(((1, 2)), (1, 2), "Error");
+}
+
 fn main() {}
index a77b08528c497ba1a741e71a2fe78b56843eab6b..0e4c9b5682dfb4748f74c808cdf56321583451ee 100644 (file)
@@ -1,34 +1,40 @@
 error: Consider removing unnecessary double parentheses
-  --> $DIR/double_parens.rs:16:5
+  --> $DIR/double_parens.rs:15:5
    |
-16 |     ((0))
+LL |     ((0))
    |     ^^^^^
    |
-   = note: `-D double-parens` implied by `-D warnings`
+   = note: `-D clippy::double-parens` implied by `-D warnings`
 
 error: Consider removing unnecessary double parentheses
-  --> $DIR/double_parens.rs:20:14
+  --> $DIR/double_parens.rs:19:14
    |
-20 |     dummy_fn((0));
+LL |     dummy_fn((0));
    |              ^^^
 
 error: Consider removing unnecessary double parentheses
-  --> $DIR/double_parens.rs:24:20
+  --> $DIR/double_parens.rs:23:20
    |
-24 |     x.dummy_method((0));
+LL |     x.dummy_method((0));
    |                    ^^^
 
 error: Consider removing unnecessary double parentheses
-  --> $DIR/double_parens.rs:28:5
+  --> $DIR/double_parens.rs:27:5
    |
-28 |     ((1, 2))
+LL |     ((1, 2))
    |     ^^^^^^^^
 
 error: Consider removing unnecessary double parentheses
-  --> $DIR/double_parens.rs:32:5
+  --> $DIR/double_parens.rs:31:5
    |
-32 |     (())
+LL |     (())
    |     ^^^^
 
-error: aborting due to 5 previous errors
+error: Consider removing unnecessary double parentheses
+  --> $DIR/double_parens.rs:53:16
+   |
+LL |     assert_eq!(((1, 2)), (1, 2), "Error");
+   |                ^^^^^^^^
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/drop_bounds.rs b/tests/ui/drop_bounds.rs
new file mode 100644 (file)
index 0000000..6d6a9dc
--- /dev/null
@@ -0,0 +1,8 @@
+#![allow(unused)]
+fn foo<T: Drop>() {}
+fn bar<T>()
+where
+    T: Drop,
+{
+}
+fn main() {}
diff --git a/tests/ui/drop_bounds.stderr b/tests/ui/drop_bounds.stderr
new file mode 100644 (file)
index 0000000..cc87913
--- /dev/null
@@ -0,0 +1,16 @@
+error: Bounds of the form `T: Drop` are useless. Use `std::mem::needs_drop` to detect if a type has drop glue.
+  --> $DIR/drop_bounds.rs:2:11
+   |
+LL | fn foo<T: Drop>() {}
+   |           ^^^^
+   |
+   = note: #[deny(clippy::drop_bounds)] on by default
+
+error: Bounds of the form `T: Drop` are useless. Use `std::mem::needs_drop` to detect if a type has drop glue.
+  --> $DIR/drop_bounds.rs:5:8
+   |
+LL |     T: Drop,
+   |        ^^^^
+
+error: aborting due to 2 previous errors
+
index 9fef06b0edeffdf69215084cb4ebc99b0003260a..9ddd6d64701a61dd615ec0b1d1f5d5451601617f 100644 (file)
@@ -1,25 +1,25 @@
-
-
-
-#![warn(drop_copy, forget_copy)]
-#![allow(toplevel_ref_arg, drop_ref, forget_ref, unused_mut)]
+#![warn(clippy::drop_copy, clippy::forget_copy)]
+#![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)]
 
 use std::mem::{drop, forget};
 use std::vec::Vec;
 
 #[derive(Copy, Clone)]
-struct SomeStruct {
-}
+struct SomeStruct {}
 
 struct AnotherStruct {
     x: u8,
     y: u8,
-    z: Vec<u8>
+    z: Vec<u8>,
 }
 
 impl Clone for AnotherStruct {
-    fn clone(& self) -> AnotherStruct {
-        AnotherStruct{x: self.x, y: self.y, z: self.z.clone()}
+    fn clone(&self) -> AnotherStruct {
+        AnotherStruct {
+            x: self.x,
+            y: self.y,
+            z: self.z.clone(),
+        }
     }
 }
 
@@ -42,7 +42,11 @@ fn main() {
     forget(s4);
     forget(s5);
 
-    let a1 = AnotherStruct {x: 255, y: 0, z: vec![1, 2, 3]};
+    let a1 = AnotherStruct {
+        x: 255,
+        y: 0,
+        z: vec![1, 2, 3],
+    };
     let a2 = &a1;
     let mut a3 = a1.clone();
     let ref a4 = a1;
index 3ea7bf9735af14cfb4e49f6fd7fde33b9038cb2c..55c840d34807653dd709c7129c3ccbbf9ddc65df 100644 (file)
@@ -1,75 +1,75 @@
 error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact.
   --> $DIR/drop_forget_copy.rs:33:5
    |
-33 |     drop(s1);
+LL |     drop(s1);
    |     ^^^^^^^^
    |
-   = note: `-D drop-copy` implied by `-D warnings`
+   = note: `-D clippy::drop-copy` implied by `-D warnings`
 note: argument has type SomeStruct
   --> $DIR/drop_forget_copy.rs:33:10
    |
-33 |     drop(s1);
+LL |     drop(s1);
    |          ^^
 
 error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact.
   --> $DIR/drop_forget_copy.rs:34:5
    |
-34 |     drop(s2);
+LL |     drop(s2);
    |     ^^^^^^^^
    |
 note: argument has type SomeStruct
   --> $DIR/drop_forget_copy.rs:34:10
    |
-34 |     drop(s2);
+LL |     drop(s2);
    |          ^^
 
 error: calls to `std::mem::drop` with a value that implements Copy. Dropping a copy leaves the original intact.
   --> $DIR/drop_forget_copy.rs:36:5
    |
-36 |     drop(s4);
+LL |     drop(s4);
    |     ^^^^^^^^
    |
 note: argument has type SomeStruct
   --> $DIR/drop_forget_copy.rs:36:10
    |
-36 |     drop(s4);
+LL |     drop(s4);
    |          ^^
 
 error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact.
   --> $DIR/drop_forget_copy.rs:39:5
    |
-39 |     forget(s1);
+LL |     forget(s1);
    |     ^^^^^^^^^^
    |
-   = note: `-D forget-copy` implied by `-D warnings`
+   = note: `-D clippy::forget-copy` implied by `-D warnings`
 note: argument has type SomeStruct
   --> $DIR/drop_forget_copy.rs:39:12
    |
-39 |     forget(s1);
+LL |     forget(s1);
    |            ^^
 
 error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact.
   --> $DIR/drop_forget_copy.rs:40:5
    |
-40 |     forget(s2);
+LL |     forget(s2);
    |     ^^^^^^^^^^
    |
 note: argument has type SomeStruct
   --> $DIR/drop_forget_copy.rs:40:12
    |
-40 |     forget(s2);
+LL |     forget(s2);
    |            ^^
 
 error: calls to `std::mem::forget` with a value that implements Copy. Forgetting a copy leaves the original intact.
   --> $DIR/drop_forget_copy.rs:42:5
    |
-42 |     forget(s4);
+LL |     forget(s4);
    |     ^^^^^^^^^^
    |
 note: argument has type SomeStruct
   --> $DIR/drop_forget_copy.rs:42:12
    |
-42 |     forget(s4);
+LL |     forget(s4);
    |            ^^
 
 error: aborting due to 6 previous errors
index e8ab6a0d5d1370e4755484aa1fb68b169d732d30..b3c75bc5764149f99db090fcca1043f697194169 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(drop_ref, forget_ref)]
-#![allow(toplevel_ref_arg, similar_names, needless_pass_by_value)]
+#![warn(clippy::drop_ref, clippy::forget_ref)]
+#![allow(clippy::toplevel_ref_arg, clippy::similar_names, clippy::needless_pass_by_value)]
 
 use std::mem::{drop, forget};
 
index 1654fdd2861ad7301f3533948589c749033a0038..8ffc369b88221a1ece3a9c458bfada38ecfebc33 100644 (file)
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:12:5
+  --> $DIR/drop_forget_ref.rs:9:5
    |
-12 |     drop(&SomeStruct);
+LL |     drop(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D drop-ref` implied by `-D warnings`
+   = note: `-D clippy::drop-ref` implied by `-D warnings`
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:12:10
+  --> $DIR/drop_forget_ref.rs:9:10
    |
-12 |     drop(&SomeStruct);
+LL |     drop(&SomeStruct);
    |          ^^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:13:5
+  --> $DIR/drop_forget_ref.rs:10:5
    |
-13 |     forget(&SomeStruct);
+LL |     forget(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D forget-ref` implied by `-D warnings`
+   = note: `-D clippy::forget-ref` implied by `-D warnings`
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:13:12
+  --> $DIR/drop_forget_ref.rs:10:12
    |
-13 |     forget(&SomeStruct);
+LL |     forget(&SomeStruct);
    |            ^^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:16:5
+  --> $DIR/drop_forget_ref.rs:13:5
    |
-16 |     drop(&owned1);
+LL |     drop(&owned1);
    |     ^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:16:10
+  --> $DIR/drop_forget_ref.rs:13:10
    |
-16 |     drop(&owned1);
+LL |     drop(&owned1);
    |          ^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:17:5
+  --> $DIR/drop_forget_ref.rs:14:5
    |
-17 |     drop(&&owned1);
+LL |     drop(&&owned1);
    |     ^^^^^^^^^^^^^^
    |
 note: argument has type &&SomeStruct
-  --> $DIR/drop_forget_ref.rs:17:10
+  --> $DIR/drop_forget_ref.rs:14:10
    |
-17 |     drop(&&owned1);
+LL |     drop(&&owned1);
    |          ^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:18:5
+  --> $DIR/drop_forget_ref.rs:15:5
    |
-18 |     drop(&mut owned1);
+LL |     drop(&mut owned1);
    |     ^^^^^^^^^^^^^^^^^
    |
 note: argument has type &mut SomeStruct
-  --> $DIR/drop_forget_ref.rs:18:10
+  --> $DIR/drop_forget_ref.rs:15:10
    |
-18 |     drop(&mut owned1);
+LL |     drop(&mut owned1);
    |          ^^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:21:5
+  --> $DIR/drop_forget_ref.rs:18:5
    |
-21 |     forget(&owned2);
+LL |     forget(&owned2);
    |     ^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:21:12
+  --> $DIR/drop_forget_ref.rs:18:12
    |
-21 |     forget(&owned2);
+LL |     forget(&owned2);
    |            ^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:22:5
+  --> $DIR/drop_forget_ref.rs:19:5
    |
-22 |     forget(&&owned2);
+LL |     forget(&&owned2);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type &&SomeStruct
-  --> $DIR/drop_forget_ref.rs:22:12
+  --> $DIR/drop_forget_ref.rs:19:12
    |
-22 |     forget(&&owned2);
+LL |     forget(&&owned2);
    |            ^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:23:5
+  --> $DIR/drop_forget_ref.rs:20:5
    |
-23 |     forget(&mut owned2);
+LL |     forget(&mut owned2);
    |     ^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type &mut SomeStruct
-  --> $DIR/drop_forget_ref.rs:23:12
+  --> $DIR/drop_forget_ref.rs:20:12
    |
-23 |     forget(&mut owned2);
+LL |     forget(&mut owned2);
    |            ^^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:27:5
+  --> $DIR/drop_forget_ref.rs:24:5
    |
-27 |     drop(reference1);
+LL |     drop(reference1);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:27:10
+  --> $DIR/drop_forget_ref.rs:24:10
    |
-27 |     drop(reference1);
+LL |     drop(reference1);
    |          ^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:28:5
+  --> $DIR/drop_forget_ref.rs:25:5
    |
-28 |     forget(&*reference1);
+LL |     forget(&*reference1);
    |     ^^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:28:12
+  --> $DIR/drop_forget_ref.rs:25:12
    |
-28 |     forget(&*reference1);
+LL |     forget(&*reference1);
    |            ^^^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:31:5
+  --> $DIR/drop_forget_ref.rs:28:5
    |
-31 |     drop(reference2);
+LL |     drop(reference2);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type &mut SomeStruct
-  --> $DIR/drop_forget_ref.rs:31:10
+  --> $DIR/drop_forget_ref.rs:28:10
    |
-31 |     drop(reference2);
+LL |     drop(reference2);
    |          ^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:33:5
+  --> $DIR/drop_forget_ref.rs:30:5
    |
-33 |     forget(reference3);
+LL |     forget(reference3);
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: argument has type &mut SomeStruct
-  --> $DIR/drop_forget_ref.rs:33:12
+  --> $DIR/drop_forget_ref.rs:30:12
    |
-33 |     forget(reference3);
+LL |     forget(reference3);
    |            ^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:36:5
+  --> $DIR/drop_forget_ref.rs:33:5
    |
-36 |     drop(reference4);
+LL |     drop(reference4);
    |     ^^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:36:10
+  --> $DIR/drop_forget_ref.rs:33:10
    |
-36 |     drop(reference4);
+LL |     drop(reference4);
    |          ^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:37:5
+  --> $DIR/drop_forget_ref.rs:34:5
    |
-37 |     forget(reference4);
+LL |     forget(reference4);
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:37:12
+  --> $DIR/drop_forget_ref.rs:34:12
    |
-37 |     forget(reference4);
+LL |     forget(reference4);
    |            ^^^^^^^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:42:5
+  --> $DIR/drop_forget_ref.rs:39:5
    |
-42 |     drop(&val);
+LL |     drop(&val);
    |     ^^^^^^^^^^
    |
 note: argument has type &T
-  --> $DIR/drop_forget_ref.rs:42:10
+  --> $DIR/drop_forget_ref.rs:39:10
    |
-42 |     drop(&val);
+LL |     drop(&val);
    |          ^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:48:5
+  --> $DIR/drop_forget_ref.rs:45:5
    |
-48 |     forget(&val);
+LL |     forget(&val);
    |     ^^^^^^^^^^^^
    |
 note: argument has type &T
-  --> $DIR/drop_forget_ref.rs:48:12
+  --> $DIR/drop_forget_ref.rs:45:12
    |
-48 |     forget(&val);
+LL |     forget(&val);
    |            ^^^^
 
 error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:56:5
+  --> $DIR/drop_forget_ref.rs:53:5
    |
-56 |     std::mem::drop(&SomeStruct);
+LL |     std::mem::drop(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:56:20
+  --> $DIR/drop_forget_ref.rs:53:20
    |
-56 |     std::mem::drop(&SomeStruct);
+LL |     std::mem::drop(&SomeStruct);
    |                    ^^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
-  --> $DIR/drop_forget_ref.rs:59:5
+  --> $DIR/drop_forget_ref.rs:56:5
    |
-59 |     std::mem::forget(&SomeStruct);
+LL |     std::mem::forget(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type &SomeStruct
-  --> $DIR/drop_forget_ref.rs:59:22
+  --> $DIR/drop_forget_ref.rs:56:22
    |
-59 |     std::mem::forget(&SomeStruct);
+LL |     std::mem::forget(&SomeStruct);
    |                      ^^^^^^^^^^^
 
 error: aborting due to 18 previous errors
index df00f56aa62152c14f53000e60d351c8b99adeff..54d748c7ce280fc2b8af175be175a0f04502dcdb 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![warn(duplicate_underscore_argument)]
+#![warn(clippy::duplicate_underscore_argument)]
 #[allow(dead_code, unused)]
 
 fn join_the_dark_side(darth: i32, _darth: i32) {}
index c926f57f154f900a6c5a4531d52660141d408fd7..f71614a5fd16e199c5688cc6dacf335c1d303a50 100644 (file)
@@ -1,10 +1,10 @@
 error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult
--> $DIR/duplicate_underscore_argument.rs:7:23
-  |
-7 | fn join_the_dark_side(darth: i32, _darth: i32) {}
-  |                       ^^^^^
-  |
-  = note: `-D duplicate-underscore-argument` implied by `-D warnings`
 --> $DIR/duplicate_underscore_argument.rs:4:23
+   |
+LL | fn join_the_dark_side(darth: i32, _darth: i32) {}
+   |                       ^^^^^
+   |
+   = note: `-D clippy::duplicate-underscore-argument` implied by `-D warnings`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/duration_subsec.fixed b/tests/ui/duration_subsec.fixed
new file mode 100644 (file)
index 0000000..ee5c786
--- /dev/null
@@ -0,0 +1,29 @@
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::duration_subsec)]
+
+use std::time::Duration;
+
+fn main() {
+    let dur = Duration::new(5, 0);
+
+    let bad_millis_1 = dur.subsec_millis();
+    let bad_millis_2 = dur.subsec_millis();
+    let good_millis = dur.subsec_millis();
+    assert_eq!(bad_millis_1, good_millis);
+    assert_eq!(bad_millis_2, good_millis);
+
+    let bad_micros = dur.subsec_micros();
+    let good_micros = dur.subsec_micros();
+    assert_eq!(bad_micros, good_micros);
+
+    // Handle refs
+    let _ = (&dur).subsec_micros();
+
+    // Handle constants
+    const NANOS_IN_MICRO: u32 = 1_000;
+    let _ = dur.subsec_micros();
+
+    // Other literals aren't linted
+    let _ = dur.subsec_nanos() / 699;
+}
index 8c75c5f2fcd8e7e4b218bbf002ebbcd8414031ce..3c9d2a286211017854d57039166bf80bb18976b7 100644 (file)
@@ -1,4 +1,6 @@
-#![warn(duration_subsec)]
+// run-rustfix
+#![allow(dead_code)]
+#![warn(clippy::duration_subsec)]
 
 use std::time::Duration;
 
index a1aacec3a75ac9b475a4456efca63527c12203dc..bd8adc2c57055b20e0b515c9f24c33dbcaab902d 100644 (file)
@@ -1,33 +1,33 @@
 error: Calling `subsec_millis()` is more concise than this calculation
--> $DIR/duration_subsec.rs:8:24
-  |
-8 |     let bad_millis_1 = dur.subsec_micros() / 1_000;
-  |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
-  |
-  = note: `-D duration-subsec` implied by `-D warnings`
 --> $DIR/duration_subsec.rs:10:24
+   |
+LL |     let bad_millis_1 = dur.subsec_micros() / 1_000;
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
+   |
+   = note: `-D clippy::duration-subsec` implied by `-D warnings`
 
 error: Calling `subsec_millis()` is more concise than this calculation
--> $DIR/duration_subsec.rs:9:24
-  |
-9 |     let bad_millis_2 = dur.subsec_nanos() / 1_000_000;
-  |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
 --> $DIR/duration_subsec.rs:11:24
+   |
+LL |     let bad_millis_2 = dur.subsec_nanos() / 1_000_000;
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()`
 
 error: Calling `subsec_micros()` is more concise than this calculation
-  --> $DIR/duration_subsec.rs:14:22
+  --> $DIR/duration_subsec.rs:16:22
    |
-14 |     let bad_micros = dur.subsec_nanos() / 1_000;
+LL |     let bad_micros = dur.subsec_nanos() / 1_000;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
 
 error: Calling `subsec_micros()` is more concise than this calculation
-  --> $DIR/duration_subsec.rs:19:13
+  --> $DIR/duration_subsec.rs:21:13
    |
-19 |     let _ = (&dur).subsec_nanos() / 1_000;
+LL |     let _ = (&dur).subsec_nanos() / 1_000;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()`
 
 error: Calling `subsec_micros()` is more concise than this calculation
-  --> $DIR/duration_subsec.rs:23:13
+  --> $DIR/duration_subsec.rs:25:13
    |
-23 |     let _ = dur.subsec_nanos() / NANOS_IN_MICRO;
+LL |     let _ = dur.subsec_nanos() / NANOS_IN_MICRO;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()`
 
 error: aborting due to 5 previous errors
index 4f019819effc00e266def274169b56ddcead578f..879b3ac398e451d3553bab28a1a76371b73f8d59 100644 (file)
@@ -1,9 +1,15 @@
-#![warn(clippy)]
-#![warn(else_if_without_else)]
+#![warn(clippy::all)]
+#![warn(clippy::else_if_without_else)]
 
-fn bla1() -> bool { unimplemented!() }
-fn bla2() -> bool { unimplemented!() }
-fn bla3() -> bool { unimplemented!() }
+fn bla1() -> bool {
+    unimplemented!()
+}
+fn bla2() -> bool {
+    unimplemented!()
+}
+fn bla3() -> bool {
+    unimplemented!()
+}
 
 fn main() {
     if bla1() {
@@ -36,7 +42,8 @@ fn main() {
 
     if bla1() {
         println!("if");
-    } else if bla2() { //~ ERROR else if without else
+    } else if bla2() {
+        //~ ERROR else if without else
         println!("else if");
     }
 
@@ -44,7 +51,8 @@ fn main() {
         println!("if");
     } else if bla2() {
         println!("else if 1");
-    } else if bla3() { //~ ERROR else if without else
+    } else if bla3() {
+        //~ ERROR else if without else
         println!("else if 2");
     }
 }
index b8a5031fbcff60e236c207eac3536fbd8d471ff7..270009067546a5f3b7852a7c694024186fcbfb81 100644 (file)
@@ -1,22 +1,27 @@
 error: if expression with an `else if`, but without a final `else`
-  --> $DIR/else_if_without_else.rs:39:12
+  --> $DIR/else_if_without_else.rs:45:12
    |
-39 |       } else if bla2() { //~ ERROR else if without else
+LL |       } else if bla2() {
    |  ____________^
-40 | |         println!("else if");
-41 | |     }
-   | |_____^ help: add an `else` block here
+LL | |         //~ ERROR else if without else
+LL | |         println!("else if");
+LL | |     }
+   | |_____^
    |
-   = note: `-D else-if-without-else` implied by `-D warnings`
+   = note: `-D clippy::else-if-without-else` implied by `-D warnings`
+   = help: add an `else` block here
 
 error: if expression with an `else if`, but without a final `else`
-  --> $DIR/else_if_without_else.rs:47:12
+  --> $DIR/else_if_without_else.rs:54:12
    |
-47 |       } else if bla3() { //~ ERROR else if without else
+LL |       } else if bla3() {
    |  ____________^
-48 | |         println!("else if 2");
-49 | |     }
-   | |_____^ help: add an `else` block here
+LL | |         //~ ERROR else if without else
+LL | |         println!("else if 2");
+LL | |     }
+   | |_____^
+   |
+   = help: add an `else` block here
 
 error: aborting due to 2 previous errors
 
index c6e6946de866ce3dc4e1667f4c059a847234f3fc..12428f29625c0298abcb627b27306c0ff25d3c99 100644 (file)
@@ -1,10 +1,6 @@
-
-
-
 #![allow(dead_code)]
-#![warn(empty_enum)]
+#![warn(clippy::empty_enum)]
 
 enum Empty {}
 
-fn main() {
-}
+fn main() {}
index ca377cee822153808cabe921037c03485452d2ad..223a14ed8772693961f506e75000ffdea65bf30e 100644 (file)
@@ -1,15 +1,15 @@
 error: enum with no variants
--> $DIR/empty_enum.rs:7:1
-  |
-7 | enum Empty {}
-  | ^^^^^^^^^^^^^
-  |
-  = note: `-D empty-enum` implied by `-D warnings`
 --> $DIR/empty_enum.rs:4:1
+   |
+LL | enum Empty {}
+   | ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::empty-enum` implied by `-D warnings`
 help: consider using the uninhabited type `!` or a wrapper around it
--> $DIR/empty_enum.rs:7:1
-  |
-7 | enum Empty {}
-  | ^^^^^^^^^^^^^
 --> $DIR/empty_enum.rs:4:1
+   |
+LL | enum Empty {}
+   | ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 30063dac0a4659ff7c88717df115b86c9b862326..5343dff9da1db26078505730abf8edcea2383d2c 100644 (file)
@@ -1,5 +1,7 @@
-
-#![warn(empty_line_after_outer_attr)]
+#![warn(clippy::empty_line_after_outer_attr)]
+#![allow(clippy::assertions_on_constants)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
 
 // This should produce a warning
 #[crate_type = "lib"]
index 7c9c7b8f349532ef9054c87fbc52e617b4184cfd..72692310391b126e9a894cef3bb9715233fec0ad 100644 (file)
@@ -1,53 +1,53 @@
 error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?
--> $DIR/empty_line_after_outer_attribute.rs:5:1
-  |
-5 | / #[crate_type = "lib"]
-6 | |
-7 | | /// some comment
-8 | | fn with_one_newline_and_comment() { assert!(true) }
-  | |_
-  |
-  = note: `-D empty-line-after-outer-attr` implied by `-D warnings`
 --> $DIR/empty_line_after_outer_attribute.rs:7:1
+   |
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | /// some comment
+LL | | fn with_one_newline_and_comment() { assert!(true) }
+   | |_
+   |
+   = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
 
 error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:17:1
+  --> $DIR/empty_line_after_outer_attribute.rs:19:1
    |
-17 | / #[crate_type = "lib"]
-18 | |
-19 | | fn with_one_newline() { assert!(true) }
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | fn with_one_newline() { assert!(true) }
    | |_
 
 error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:22:1
+  --> $DIR/empty_line_after_outer_attribute.rs:24:1
    |
-22 | / #[crate_type = "lib"]
-23 | |
-24 | |
-25 | | fn with_two_newlines() { assert!(true) }
+LL | / #[crate_type = "lib"]
+LL | |
+LL | |
+LL | | fn with_two_newlines() { assert!(true) }
    | |_
 
 error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:29:1
+  --> $DIR/empty_line_after_outer_attribute.rs:31:1
    |
-29 | / #[crate_type = "lib"]
-30 | |
-31 | | enum Baz {
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | enum Baz {
    | |_
 
 error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:37:1
+  --> $DIR/empty_line_after_outer_attribute.rs:39:1
    |
-37 | / #[crate_type = "lib"]
-38 | |
-39 | | struct Foo {
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | struct Foo {
    | |_
 
 error: Found an empty line after an outer attribute. Perhaps you forgot to add a '!' to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:45:1
+  --> $DIR/empty_line_after_outer_attribute.rs:47:1
    |
-45 | / #[crate_type = "lib"]
-46 | |
-47 | | mod foo {
+LL | / #[crate_type = "lib"]
+LL | |
+LL | | mod foo {
    | |_
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs
new file mode 100644 (file)
index 0000000..fb9f2cb
--- /dev/null
@@ -0,0 +1,52 @@
+// aux-build:macro_rules.rs
+
+#![warn(clippy::empty_loop)]
+#![allow(clippy::unused_label)]
+
+#[macro_use]
+extern crate macro_rules;
+
+fn should_trigger() {
+    loop {}
+    loop {
+        loop {}
+    }
+
+    'outer: loop {
+        'inner: loop {}
+    }
+}
+
+fn should_not_trigger() {
+    loop {
+        panic!("This is fine")
+    }
+    let ten_millis = std::time::Duration::from_millis(10);
+    loop {
+        std::thread::sleep(ten_millis)
+    }
+
+    #[allow(clippy::never_loop)]
+    'outer: loop {
+        'inner: loop {
+            break 'inner;
+        }
+        break 'outer;
+    }
+
+    // Make sure `allow` works for this lint
+    #[allow(clippy::empty_loop)]
+    loop {}
+
+    // We don't lint loops inside macros
+    macro_rules! foo {
+        () => {
+            loop {}
+        };
+    }
+
+    // We don't lint external macros
+    foofoo!()
+}
+
+fn main() {}
diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr
new file mode 100644 (file)
index 0000000..41b7990
--- /dev/null
@@ -0,0 +1,22 @@
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/empty_loop.rs:10:5
+   |
+LL |     loop {}
+   |     ^^^^^^^
+   |
+   = note: `-D clippy::empty-loop` implied by `-D warnings`
+
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/empty_loop.rs:12:9
+   |
+LL |         loop {}
+   |         ^^^^^^^
+
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/empty_loop.rs:16:9
+   |
+LL |         'inner: loop {}
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index ccbc7038f13600aa88b9b6ccd719cab2081c6c1c..00d496e36f6c491a62a884c9c19d8e9e00e599ff 100644 (file)
@@ -1,8 +1,5 @@
-
-
-#![allow(unused, needless_pass_by_value)]
-
-#![warn(map_entry)]
+#![allow(unused, clippy::needless_pass_by_value)]
+#![warn(clippy::map_entry)]
 
 use std::collections::{BTreeMap, HashMap};
 use std::hash::Hash;
 fn foo() {}
 
 fn insert_if_absent0<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
-    if !m.contains_key(&k) { m.insert(k, v); }
+    if !m.contains_key(&k) {
+        m.insert(k, v);
+    }
 }
 
 fn insert_if_absent1<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
-    if !m.contains_key(&k) { foo(); m.insert(k, v); }
+    if !m.contains_key(&k) {
+        foo();
+        m.insert(k, v);
+    }
 }
 
 fn insert_if_absent2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
-    if !m.contains_key(&k) { m.insert(k, v) } else { None };
+    if !m.contains_key(&k) {
+        m.insert(k, v)
+    } else {
+        None
+    };
 }
 
 fn insert_if_present2<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
-    if m.contains_key(&k) { None } else { m.insert(k, v) };
+    if m.contains_key(&k) {
+        None
+    } else {
+        m.insert(k, v)
+    };
 }
 
 fn insert_if_absent3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
-    if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
+    if !m.contains_key(&k) {
+        foo();
+        m.insert(k, v)
+    } else {
+        None
+    };
 }
 
 fn insert_if_present3<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, v: V) {
-    if m.contains_key(&k) { None } else { foo(); m.insert(k, v) };
+    if m.contains_key(&k) {
+        None
+    } else {
+        foo();
+        m.insert(k, v)
+    };
 }
 
 fn insert_in_btreemap<K: Ord, V>(m: &mut BTreeMap<K, V>, k: K, v: V) {
-    if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
+    if !m.contains_key(&k) {
+        foo();
+        m.insert(k, v)
+    } else {
+        None
+    };
 }
 
 fn insert_other_if_absent<K: Eq + Hash, V>(m: &mut HashMap<K, V>, k: K, o: K, v: V) {
-    if !m.contains_key(&k) { m.insert(o, v); }
+    if !m.contains_key(&k) {
+        m.insert(o, v);
+    }
 }
 
-fn main() {
-}
+fn main() {}
index 09c4a8822802a0ab01ebfd386abe70ccce98c834..efacec1e77787a02f39b1accce6704de0a713856 100644 (file)
@@ -1,46 +1,74 @@
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:13:5
+  --> $DIR/entry.rs:10:5
    |
-13 |     if !m.contains_key(&k) { m.insert(k, v); }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k).or_insert(v)`
+LL | /     if !m.contains_key(&k) {
+LL | |         m.insert(k, v);
+LL | |     }
+   | |_____^ help: consider using: `m.entry(k).or_insert(v)`
    |
-   = note: `-D map-entry` implied by `-D warnings`
+   = note: `-D clippy::map-entry` implied by `-D warnings`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:17:5
+  --> $DIR/entry.rs:16:5
    |
-17 |     if !m.contains_key(&k) { foo(); m.insert(k, v); }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
+LL | /     if !m.contains_key(&k) {
+LL | |         foo();
+LL | |         m.insert(k, v);
+LL | |     }
+   | |_____^ help: consider using: `m.entry(k)`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:21:5
+  --> $DIR/entry.rs:23:5
    |
-21 |     if !m.contains_key(&k) { m.insert(k, v) } else { None };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
+LL | /     if !m.contains_key(&k) {
+LL | |         m.insert(k, v)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: consider using: `m.entry(k)`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:25:5
+  --> $DIR/entry.rs:31:5
    |
-25 |     if m.contains_key(&k) { None } else { m.insert(k, v) };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
+LL | /     if m.contains_key(&k) {
+LL | |         None
+LL | |     } else {
+LL | |         m.insert(k, v)
+LL | |     };
+   | |_____^ help: consider using: `m.entry(k)`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:29:5
+  --> $DIR/entry.rs:39:5
    |
-29 |     if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
+LL | /     if !m.contains_key(&k) {
+LL | |         foo();
+LL | |         m.insert(k, v)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: consider using: `m.entry(k)`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:33:5
+  --> $DIR/entry.rs:48:5
    |
-33 |     if m.contains_key(&k) { None } else { foo(); m.insert(k, v) };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
+LL | /     if m.contains_key(&k) {
+LL | |         None
+LL | |     } else {
+LL | |         foo();
+LL | |         m.insert(k, v)
+LL | |     };
+   | |_____^ help: consider using: `m.entry(k)`
 
 error: usage of `contains_key` followed by `insert` on a `BTreeMap`
-  --> $DIR/entry.rs:37:5
+  --> $DIR/entry.rs:57:5
    |
-37 |     if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)`
+LL | /     if !m.contains_key(&k) {
+LL | |         foo();
+LL | |         m.insert(k, v)
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: consider using: `m.entry(k)`
 
 error: aborting due to 7 previous errors
 
index efb37fbe49d2d0ad1e73b0b11b6d773f695ca99b..e7b2526ca50bbcd61b4cb1d17c4bf3f64960626b 100644 (file)
@@ -1,7 +1,5 @@
-
-
-#![warn(clippy, clippy_pedantic)]
-#![allow(unused_imports, dead_code, missing_docs_in_private_items)]
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(unused_imports, dead_code, clippy::missing_docs_in_private_items)]
 
 use std::cmp::Ordering::*;
 
@@ -24,8 +22,7 @@ mod tests {
 }
 
 #[allow(non_snake_case)]
-mod CamelCaseName {
-}
+mod CamelCaseName {}
 
 use CamelCaseName::*;
 
index 2d53618c1b18dfe73078c225f96a09887fbc613f..a301703c2988dca63852052eb55e3836e362d5af 100644 (file)
@@ -1,15 +1,15 @@
 error: don't use glob imports for enum variants
--> $DIR/enum_glob_use.rs:6:1
-  |
-6 | use std::cmp::Ordering::*;
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D enum-glob-use` implied by `-D warnings`
 --> $DIR/enum_glob_use.rs:4:1
+   |
+LL | use std::cmp::Ordering::*;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::enum-glob-use` implied by `-D warnings`
 
 error: don't use glob imports for enum variants
-  --> $DIR/enum_glob_use.rs:12:1
+  --> $DIR/enum_glob_use.rs:10:1
    |
-12 | use self::Enum::*;
+LL | use self::Enum::*;
    | ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
index 222c76c25b76344361b8b9a6e1a5d0afbf559b09..f3bbd3d96260eb537284d939569c790e2ea62b01 100644 (file)
@@ -1,13 +1,15 @@
 #![feature(non_ascii_idents)]
-
-#![warn(clippy, pub_enum_variant_names)]
+#![warn(clippy::all, clippy::pub_enum_variant_names)]
+#![allow(non_camel_case_types)]
 
 enum FakeCallType {
-    CALL, CREATE
+    CALL,
+    CREATE,
 }
 
 enum FakeCallType2 {
-    CALL, CREATELL
+    CALL,
+    CREATELL,
 }
 
 enum Foo {
@@ -37,7 +39,8 @@ enum BadCallType {
     CallTypeDestroy,
 }
 
-enum TwoCallType { // no error
+enum TwoCallType {
+    // no error
     CallTypeCall,
     CallTypeCreate,
 }
@@ -48,7 +51,8 @@ enum Consts {
     ConstantLie,
 }
 
-enum Two { // no error here
+enum Two {
+    // no error here
     ConstantInt,
     ConstantInfer,
 }
@@ -93,7 +97,7 @@ pub enum PubSeall {
     WithOut,
 }
 
-#[allow(pub_enum_variant_names)]
+#[allow(clippy::pub_enum_variant_names)]
 mod allowed {
     pub enum PubAllowed {
         SomeThis,
index e33e29ec78e1228452a834d1d42f93c01f0b48dd..2835391de7f5838a7013ff98feb3357826c03df7 100644 (file)
 error: Variant name ends with the enum's name
-  --> $DIR/enum_variants.rs:14:5
+  --> $DIR/enum_variants.rs:16:5
    |
-14 |     cFoo,
+LL |     cFoo,
    |     ^^^^
    |
-   = note: `-D enum-variant-names` implied by `-D warnings`
+   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 
 error: Variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:25:5
+  --> $DIR/enum_variants.rs:27:5
    |
-25 |     FoodGood,
+LL |     FoodGood,
    |     ^^^^^^^^
 
 error: Variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:26:5
+  --> $DIR/enum_variants.rs:28:5
    |
-26 |     FoodMiddle,
+LL |     FoodMiddle,
    |     ^^^^^^^^^^
 
 error: Variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:27:5
+  --> $DIR/enum_variants.rs:29:5
    |
-27 |     FoodBad,
+LL |     FoodBad,
    |     ^^^^^^^
 
 error: All variants have the same prefix: `Food`
-  --> $DIR/enum_variants.rs:24:1
+  --> $DIR/enum_variants.rs:26:1
    |
-24 | / enum Food {
-25 | |     FoodGood,
-26 | |     FoodMiddle,
-27 | |     FoodBad,
-28 | | }
+LL | / enum Food {
+LL | |     FoodGood,
+LL | |     FoodMiddle,
+LL | |     FoodBad,
+LL | | }
    | |_^
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: All variants have the same prefix: `CallType`
-  --> $DIR/enum_variants.rs:34:1
+  --> $DIR/enum_variants.rs:36:1
    |
-34 | / enum BadCallType {
-35 | |     CallTypeCall,
-36 | |     CallTypeCreate,
-37 | |     CallTypeDestroy,
-38 | | }
+LL | / enum BadCallType {
+LL | |     CallTypeCall,
+LL | |     CallTypeCreate,
+LL | |     CallTypeDestroy,
+LL | | }
    | |_^
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: All variants have the same prefix: `Constant`
-  --> $DIR/enum_variants.rs:45:1
+  --> $DIR/enum_variants.rs:48:1
    |
-45 | / enum Consts {
-46 | |     ConstantInt,
-47 | |     ConstantCake,
-48 | |     ConstantLie,
-49 | | }
+LL | / enum Consts {
+LL | |     ConstantInt,
+LL | |     ConstantCake,
+LL | |     ConstantLie,
+LL | | }
    | |_^
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: All variants have the same prefix: `With`
-  --> $DIR/enum_variants.rs:78:1
+  --> $DIR/enum_variants.rs:82:1
    |
-78 | / enum Seallll {
-79 | |     WithOutCake,
-80 | |     WithOutTea,
-81 | |     WithOut,
-82 | | }
+LL | / enum Seallll {
+LL | |     WithOutCake,
+LL | |     WithOutTea,
+LL | |     WithOut,
+LL | | }
    | |_^
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: All variants have the same prefix: `Prefix`
-  --> $DIR/enum_variants.rs:84:1
+  --> $DIR/enum_variants.rs:88:1
    |
-84 | / enum NonCaps {
-85 | |     Prefix的,
-86 | |     PrefixTea,
-87 | |     PrefixCake,
-88 | | }
+LL | / enum NonCaps {
+LL | |     Prefix的,
+LL | |     PrefixTea,
+LL | |     PrefixCake,
+LL | | }
    | |_^
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: All variants have the same prefix: `With`
-  --> $DIR/enum_variants.rs:90:1
+  --> $DIR/enum_variants.rs:94:1
    |
-90 | / pub enum PubSeall {
-91 | |     WithOutCake,
-92 | |     WithOutTea,
-93 | |     WithOut,
-94 | | }
+LL | / pub enum PubSeall {
+LL | |     WithOutCake,
+LL | |     WithOutTea,
+LL | |     WithOut,
+LL | | }
    | |_^
    |
-   = note: `-D pub-enum-variant-names` implied by `-D warnings`
+   = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: aborting due to 10 previous errors
index 618603683e83f69a4b379c71b12a2f575e6cf6ae..789542b13518589dad3e4c1a010842b6eb3dc8f7 100644 (file)
@@ -1,8 +1,6 @@
 // ignore-x86
 
-
-#![warn(clippy)]
-
+#![warn(clippy::all)]
 #![allow(unused)]
 
 #[repr(usize)]
@@ -50,5 +48,4 @@ trait Trait {
 }
 */
 
-fn main() {
-}
+fn main() {}
index d6a137c6fe4dfb84af5c1c1ece94ca4bb20a3902..c3390405094f2eaadb05d6b6969724af40881b1f 100644 (file)
@@ -1,51 +1,51 @@
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:10:5
+  --> $DIR/enums_clike.rs:8:5
    |
-10 |     X = 0x1_0000_0000,
+LL |     X = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D enum-clike-unportable-variant` implied by `-D warnings`
+   = note: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings`
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:17:5
+  --> $DIR/enums_clike.rs:15:5
    |
-17 |     X = 0x1_0000_0000,
+LL |     X = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:20:5
+  --> $DIR/enums_clike.rs:18:5
    |
-20 |     A = 0xFFFF_FFFF,
+LL |     A = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:27:5
+  --> $DIR/enums_clike.rs:25:5
    |
-27 |     Z = 0xFFFF_FFFF,
+LL |     Z = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:28:5
+  --> $DIR/enums_clike.rs:26:5
    |
-28 |     A = 0x1_0000_0000,
+LL |     A = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:30:5
+  --> $DIR/enums_clike.rs:28:5
    |
-30 |     C = (std::i32::MIN as isize) - 1,
+LL |     C = (std::i32::MIN as isize) - 1,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:36:5
+  --> $DIR/enums_clike.rs:34:5
    |
-36 |     Z = 0xFFFF_FFFF,
+LL |     Z = 0xFFFF_FFFF,
    |     ^^^^^^^^^^^^^^^
 
 error: Clike enum variant discriminant is not portable to 32-bit targets
-  --> $DIR/enums_clike.rs:37:5
+  --> $DIR/enums_clike.rs:35:5
    |
-37 |     A = 0x1_0000_0000,
+LL |     A = 0x1_0000_0000,
    |     ^^^^^^^^^^^^^^^^^
 
 error: aborting due to 8 previous errors
index ef573b2b91af4dbf90ae2d119bfede6aa9234b4f..cc0935ddb799cedabdf7449bc6382d4267a73db6 100644 (file)
@@ -1,10 +1,8 @@
-
-
-
-#[warn(eq_op)]
-#[allow(identity_op, double_parens, many_single_char_names)]
-#[allow(no_effect, unused_variables, unnecessary_operation, short_circuit_statement)]
-#[warn(nonminimal_bool)]
+#[rustfmt::skip]
+#[warn(clippy::eq_op)]
+#[allow(clippy::identity_op, clippy::double_parens, clippy::many_single_char_names)]
+#[allow(clippy::no_effect, unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
+#[warn(clippy::nonminimal_bool)]
 fn main() {
     // simple values and comparisons
     1 == 1;
@@ -97,6 +95,7 @@ fn bitand(self, rhs: &'a Y) -> Y {
     const D: u32 = A / A;
 }
 
+#[rustfmt::skip]
 macro_rules! check_if_named_foo {
     ($expression:expr) => (
         if stringify!($expression) == "foo" {
index ccf366062089cd436d57ff392bcc563fd20d5a05..2dabaf0d4db9e8243d86b1ab4c160afe978d9392 100644 (file)
 error: this boolean expression can be simplified
-  --> $DIR/eq_op.rs:37:5
+  --> $DIR/eq_op.rs:35:5
    |
-37 |     true && true;
+LL |     true && true;
    |     ^^^^^^^^^^^^ help: try: `true`
    |
-   = note: `-D nonminimal-bool` implied by `-D warnings`
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
 
 error: this boolean expression can be simplified
-  --> $DIR/eq_op.rs:39:5
+  --> $DIR/eq_op.rs:37:5
    |
-39 |     true || true;
+LL |     true || true;
    |     ^^^^^^^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> $DIR/eq_op.rs:45:5
+  --> $DIR/eq_op.rs:43:5
    |
-45 |     a == b && b == a;
+LL |     a == b && b == a;
    |     ^^^^^^^^^^^^^^^^ help: try: `a == b`
 
 error: this boolean expression can be simplified
-  --> $DIR/eq_op.rs:46:5
+  --> $DIR/eq_op.rs:44:5
    |
-46 |     a != b && b != a;
+LL |     a != b && b != a;
    |     ^^^^^^^^^^^^^^^^ help: try: `a != b`
 
 error: this boolean expression can be simplified
-  --> $DIR/eq_op.rs:47:5
+  --> $DIR/eq_op.rs:45:5
    |
-47 |     a < b && b > a;
+LL |     a < b && b > a;
    |     ^^^^^^^^^^^^^^ help: try: `a < b`
 
 error: this boolean expression can be simplified
-  --> $DIR/eq_op.rs:48:5
+  --> $DIR/eq_op.rs:46:5
    |
-48 |     a <= b && b >= a;
+LL |     a <= b && b >= a;
    |     ^^^^^^^^^^^^^^^^ help: try: `a <= b`
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:10:5
+  --> $DIR/eq_op.rs:8:5
    |
-10 |     1 == 1;
+LL |     1 == 1;
    |     ^^^^^^
    |
-   = note: `-D eq-op` implied by `-D warnings`
+   = note: `-D clippy::eq-op` implied by `-D warnings`
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:11:5
+  --> $DIR/eq_op.rs:9:5
    |
-11 |     "no" == "no";
+LL |     "no" == "no";
    |     ^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> $DIR/eq_op.rs:13:5
+  --> $DIR/eq_op.rs:11:5
    |
-13 |     false != false;
+LL |     false != false;
    |     ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `<`
-  --> $DIR/eq_op.rs:14:5
+  --> $DIR/eq_op.rs:12:5
    |
-14 |     1.5 < 1.5;
+LL |     1.5 < 1.5;
    |     ^^^^^^^^^
 
 error: equal expressions as operands to `>=`
-  --> $DIR/eq_op.rs:15:5
+  --> $DIR/eq_op.rs:13:5
    |
-15 |     1u64 >= 1u64;
+LL |     1u64 >= 1u64;
    |     ^^^^^^^^^^^^
 
 error: equal expressions as operands to `&`
-  --> $DIR/eq_op.rs:18:5
+  --> $DIR/eq_op.rs:16:5
    |
-18 |     (1 as u64) & (1 as u64);
+LL |     (1 as u64) & (1 as u64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `^`
-  --> $DIR/eq_op.rs:19:5
+  --> $DIR/eq_op.rs:17:5
    |
-19 |     1 ^ ((((((1))))));
+LL |     1 ^ ((((((1))))));
    |     ^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `<`
-  --> $DIR/eq_op.rs:22:5
+  --> $DIR/eq_op.rs:20:5
    |
-22 |     (-(2) < -(2));
+LL |     (-(2) < -(2));
    |     ^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:23:5
+  --> $DIR/eq_op.rs:21:5
    |
-23 |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&`
-  --> $DIR/eq_op.rs:23:6
+  --> $DIR/eq_op.rs:21:6
    |
-23 |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
    |      ^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&`
-  --> $DIR/eq_op.rs:23:27
+  --> $DIR/eq_op.rs:21:27
    |
-23 |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
    |                           ^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:24:5
+  --> $DIR/eq_op.rs:22:5
    |
-24 |     (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
+LL |     (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> $DIR/eq_op.rs:27:5
+  --> $DIR/eq_op.rs:25:5
    |
-27 |     ([1] != [1]);
+LL |     ([1] != [1]);
    |     ^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> $DIR/eq_op.rs:28:5
+  --> $DIR/eq_op.rs:26:5
    |
-28 |     ((1, 2) != (1, 2));
+LL |     ((1, 2) != (1, 2));
    |     ^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:32:5
+  --> $DIR/eq_op.rs:30:5
    |
-32 |     1 + 1 == 2;
+LL |     1 + 1 == 2;
    |     ^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:33:5
+  --> $DIR/eq_op.rs:31:5
    |
-33 |     1 - 1 == 0;
+LL |     1 - 1 == 0;
    |     ^^^^^^^^^^
 
 error: equal expressions as operands to `-`
-  --> $DIR/eq_op.rs:33:5
+  --> $DIR/eq_op.rs:31:5
    |
-33 |     1 - 1 == 0;
+LL |     1 - 1 == 0;
    |     ^^^^^
 
 error: equal expressions as operands to `-`
-  --> $DIR/eq_op.rs:35:5
+  --> $DIR/eq_op.rs:33:5
    |
-35 |     1 - 1;
+LL |     1 - 1;
    |     ^^^^^
 
 error: equal expressions as operands to `/`
-  --> $DIR/eq_op.rs:36:5
+  --> $DIR/eq_op.rs:34:5
    |
-36 |     1 / 1;
+LL |     1 / 1;
    |     ^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:37:5
+  --> $DIR/eq_op.rs:35:5
    |
-37 |     true && true;
+LL |     true && true;
    |     ^^^^^^^^^^^^
 
 error: equal expressions as operands to `||`
-  --> $DIR/eq_op.rs:39:5
+  --> $DIR/eq_op.rs:37:5
    |
-39 |     true || true;
+LL |     true || true;
    |     ^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:45:5
+  --> $DIR/eq_op.rs:43:5
    |
-45 |     a == b && b == a;
+LL |     a == b && b == a;
    |     ^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:46:5
+  --> $DIR/eq_op.rs:44:5
    |
-46 |     a != b && b != a;
+LL |     a != b && b != a;
    |     ^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:47:5
+  --> $DIR/eq_op.rs:45:5
    |
-47 |     a < b && b > a;
+LL |     a < b && b > a;
    |     ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:48:5
+  --> $DIR/eq_op.rs:46:5
    |
-48 |     a <= b && b >= a;
+LL |     a <= b && b >= a;
    |     ^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:51:5
+  --> $DIR/eq_op.rs:49:5
    |
-51 |     a == a;
+LL |     a == a;
    |     ^^^^^^
 
 error: taken reference of right operand
-  --> $DIR/eq_op.rs:89:13
+  --> $DIR/eq_op.rs:87:13
    |
-89 |     let z = x & &y;
+LL |     let z = x & &y;
    |             ^^^^--
    |                 |
    |                 help: use the right value directly: `y`
    |
-   = note: `-D op-ref` implied by `-D warnings`
+   = note: `-D clippy::op-ref` implied by `-D warnings`
 
 error: equal expressions as operands to `/`
-  --> $DIR/eq_op.rs:97:20
+  --> $DIR/eq_op.rs:95:20
    |
-97 |     const D: u32 = A / A;
+LL |     const D: u32 = A / A;
    |                    ^^^^^
 
 error: aborting due to 34 previous errors
index e5143146f2666b0bff6c5f5e8b852f4009936bcc..1540062a4bc3ea106dbe64d46462f7016e5caf25 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#[allow(no_effect)]
-#[warn(erasing_op)]
+#[allow(clippy::no_effect)]
+#[warn(clippy::erasing_op)]
 fn main() {
     let x: u8 = 0;
 
index 310c41c541bc0ad9f624890edd3f92a352d1eb21..e54ce85f98ec78b4ddf7730bd064ebfc9a258a4d 100644 (file)
@@ -1,21 +1,21 @@
 error: this operation will always return zero. This is likely not the intended outcome
--> $DIR/erasing_op.rs:9:5
-  |
-9 |     x * 0;
-  |     ^^^^^
-  |
-  = note: `-D erasing-op` implied by `-D warnings`
 --> $DIR/erasing_op.rs:6:5
+   |
+LL |     x * 0;
+   |     ^^^^^
+   |
+   = note: `-D clippy::erasing-op` implied by `-D warnings`
 
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/erasing_op.rs:10:5
+  --> $DIR/erasing_op.rs:7:5
    |
-10 |     0 & x;
+LL |     0 & x;
    |     ^^^^^
 
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/erasing_op.rs:11:5
+  --> $DIR/erasing_op.rs:8:5
    |
-11 |     0 / x;
+LL |     0 / x;
    |     ^^^^^
 
 error: aborting due to 3 previous errors
index 7a888f0191411463658e17f63d6e704c41f6c26e..e3f78182fd13edb48a8fce3b7786c42cf20d594c 100644 (file)
@@ -1,14 +1,12 @@
 #![feature(box_syntax)]
-
-#![allow(warnings, clippy)]
-
-#![warn(boxed_local)]
+#![allow(clippy::borrowed_box, clippy::needless_pass_by_value, clippy::unused_unit)]
+#![warn(clippy::boxed_local)]
 
 #[derive(Clone)]
 struct A;
 
 impl A {
-    fn foo(&self){}
+    fn foo(&self) {}
 }
 
 trait Z {
@@ -21,8 +19,7 @@ fn bar(&self) {
     }
 }
 
-fn main() {
-}
+fn main() {}
 
 fn ok_box_trait(boxed_trait: &Box<Z>) {
     let boxed_local = boxed_trait;
@@ -60,8 +57,7 @@ fn warn_pass() {
 }
 
 fn nowarn_return() -> Box<A> {
-    let fx = box A;
-    fx // moved out, "escapes"
+    box A // moved out, "escapes"
 }
 
 fn nowarn_move() {
@@ -78,11 +74,9 @@ fn nowarn_pass() {
     take_box(&bx); // fn needs &Box
 }
 
-
 fn take_box(x: &Box<A>) {}
 fn take_ref(x: &A) {}
 
-
 fn nowarn_ref_take() {
     // false positive, should actually warn
     let x = box A;
@@ -93,14 +87,15 @@ fn nowarn_ref_take() {
 fn nowarn_match() {
     let x = box A; // moved into a match
     match x {
-        y => drop(y)
+        y => drop(y),
     }
 }
 
 fn warn_match() {
     let x = box A;
-    match &x { // not moved
-        ref y => ()
+    match &x {
+        // not moved
+        ref y => (),
     }
 }
 
@@ -108,12 +103,12 @@ fn nowarn_large_array() {
     // should not warn, is large array
     // and should not be on stack
     let x = box [1; 10000];
-    match &x { // not moved
-        ref y => ()
+    match &x {
+        // not moved
+        ref y => (),
     }
 }
 
-
 /// ICE regression test
 pub trait Foo {
     type Item;
@@ -127,5 +122,49 @@ pub struct PeekableSeekable<I: Foo> {
     _peeked: I::Item,
 }
 
-pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {
+pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
+
+/// Regression for #916, #1123
+///
+/// This shouldn't warn for `boxed_local`as the implementation of a trait
+/// can't change much about the trait definition.
+trait BoxedAction {
+    fn do_sth(self: Box<Self>);
+}
+
+impl BoxedAction for u64 {
+    fn do_sth(self: Box<Self>) {
+        println!("{}", *self)
+    }
+}
+
+/// Regression for #1478
+///
+/// This shouldn't warn for `boxed_local`as self itself is a box type.
+trait MyTrait {
+    fn do_sth(self);
+}
+
+impl<T> MyTrait for Box<T> {
+    fn do_sth(self) {}
+}
+
+// Issue #3739 - capture in closures
+mod issue_3739 {
+    use super::A;
+
+    fn consume<T>(_: T) {}
+    fn borrow<T>(_: &T) {}
+
+    fn closure_consume(x: Box<A>) {
+        let _ = move || {
+            consume(x);
+        };
+    }
+
+    fn closure_borrow(x: Box<A>) {
+        let _ = || {
+            borrow(&x);
+        };
+    }
 }
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3944acd87f2878fe7507b7e3eb32beeefa92ca12 100644 (file)
@@ -0,0 +1,22 @@
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:34:13
+   |
+LL | fn warn_arg(x: Box<A>) {
+   |             ^
+   |
+   = note: `-D clippy::boxed-local` implied by `-D warnings`
+
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:125:12
+   |
+LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
+   |            ^^^^^^^^^^^
+
+error: local variable doesn't need to be boxed here
+  --> $DIR/escape_analysis.rs:165:23
+   |
+LL |     fn closure_borrow(x: Box<A>) {
+   |                       ^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed
new file mode 100644 (file)
index 0000000..a3e5795
--- /dev/null
@@ -0,0 +1,179 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::no_effect,
+    clippy::redundant_closure_call,
+    clippy::many_single_char_names,
+    clippy::needless_pass_by_value,
+    clippy::option_map_unit_fn,
+    clippy::trivially_copy_pass_by_ref
+)]
+#![warn(
+    clippy::redundant_closure,
+    clippy::redundant_closure_for_method_calls,
+    clippy::needless_borrow
+)]
+
+use std::path::PathBuf;
+
+fn main() {
+    let a = Some(1u8).map(foo);
+    meta(foo);
+    let c = Some(1u8).map({1+2; foo});
+    let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
+    all(&[1, 2, 3], &2, |x, y| below(x, y)); //is adjusted
+    unsafe {
+        Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
+    }
+
+    // See #815
+    let e = Some(1u8).map(|a| divergent(a));
+    let e = Some(1u8).map(generic);
+    let e = Some(1u8).map(generic);
+    // See #515
+    let a: Option<Box<::std::ops::Deref<Target = [i32]>>> =
+        Some(vec![1i32, 2]).map(|v| -> Box<::std::ops::Deref<Target = [i32]>> { Box::new(v) });
+}
+
+trait TestTrait {
+    fn trait_foo(self) -> bool;
+    fn trait_foo_ref(&self) -> bool;
+}
+
+struct TestStruct<'a> {
+    some_ref: &'a i32,
+}
+
+impl<'a> TestStruct<'a> {
+    fn foo(self) -> bool {
+        false
+    }
+    unsafe fn foo_unsafe(self) -> bool {
+        true
+    }
+}
+
+impl<'a> TestTrait for TestStruct<'a> {
+    fn trait_foo(self) -> bool {
+        false
+    }
+    fn trait_foo_ref(&self) -> bool {
+        false
+    }
+}
+
+impl<'a> std::ops::Deref for TestStruct<'a> {
+    type Target = char;
+    fn deref(&self) -> &char {
+        &'a'
+    }
+}
+
+fn test_redundant_closures_containing_method_calls() {
+    let i = 10;
+    let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
+    let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
+    let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref());
+    let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
+    let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
+    let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
+    unsafe {
+        let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
+    }
+    let e = Some("str").map(std::string::ToString::to_string);
+    let e = Some("str").map(str::to_string);
+    let e = Some('a').map(char::to_uppercase);
+    let e = Some('a').map(char::to_uppercase);
+    let e: std::vec::Vec<usize> = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
+    let p = Some(PathBuf::new());
+    let e = p.as_ref().and_then(|s| s.to_str());
+    let c = Some(TestStruct { some_ref: &i })
+        .as_ref()
+        .map(|c| c.to_ascii_uppercase());
+
+    fn test_different_borrow_levels<T>(t: &[&T])
+    where
+        T: TestTrait,
+    {
+        t.iter().filter(|x| x.trait_foo_ref());
+        t.iter().map(|x| x.trait_foo_ref());
+    }
+
+    let mut some = Some(|x| x * x);
+    let arr = [Ok(1), Err(2)];
+    let _: Vec<_> = arr.iter().map(|x| x.map_err(some.take().unwrap())).collect();
+}
+
+struct Thunk<T>(Box<FnMut() -> T>);
+
+impl<T> Thunk<T> {
+    fn new<F: 'static + FnOnce() -> T>(f: F) -> Thunk<T> {
+        let mut option = Some(f);
+        // This should not trigger redundant_closure (#1439)
+        Thunk(Box::new(move || option.take().unwrap()()))
+    }
+
+    fn unwrap(self) -> T {
+        let Thunk(mut f) = self;
+        f()
+    }
+}
+
+fn foobar() {
+    let thunk = Thunk::new(|| println!("Hello, world!"));
+    thunk.unwrap()
+}
+
+fn meta<F>(f: F)
+where
+    F: Fn(u8),
+{
+    f(1u8)
+}
+
+fn foo(_: u8) {}
+
+fn foo2(_: u8) -> u8 {
+    1u8
+}
+
+fn all<X, F>(x: &[X], y: &X, f: F) -> bool
+where
+    F: Fn(&X, &X) -> bool,
+{
+    x.iter().all(|e| f(e, y))
+}
+
+fn below(x: &u8, y: &u8) -> bool {
+    x < y
+}
+
+unsafe fn unsafe_fn(_: u8) {}
+
+fn divergent(_: u8) -> ! {
+    unimplemented!()
+}
+
+fn generic<T>(_: T) -> u8 {
+    0
+}
+
+fn passes_fn_mut(mut x: Box<dyn FnMut()>) {
+    requires_fn_once(|| x());
+}
+fn requires_fn_once<T: FnOnce()>(_: T) {}
+
+fn test_redundant_closure_with_function_pointer() {
+    type FnPtrType = fn(u8);
+    let foo_ptr: FnPtrType = foo;
+    let a = Some(1u8).map(foo_ptr);
+}
+
+fn test_redundant_closure_with_another_closure() {
+    let closure = |a| println!("{}", a);
+    let a = Some(1u8).map(closure);
+}
index 6e0b6f8cacd7eba46f055252407c88d9546d315a..58adf21b1d5ed78125627f2e18ceab9eae864522 100644 (file)
@@ -1,7 +1,21 @@
+// run-rustfix
 
+#![allow(
+    unused,
+    clippy::no_effect,
+    clippy::redundant_closure_call,
+    clippy::many_single_char_names,
+    clippy::needless_pass_by_value,
+    clippy::option_map_unit_fn,
+    clippy::trivially_copy_pass_by_ref
+)]
+#![warn(
+    clippy::redundant_closure,
+    clippy::redundant_closure_for_method_calls,
+    clippy::needless_borrow
+)]
 
-#![allow(unknown_lints, unused, no_effect, redundant_closure_call, many_single_char_names, needless_pass_by_value, option_map_unit_fn, trivially_copy_pass_by_ref)]
-#![warn(redundant_closure, needless_borrow)]
+use std::path::PathBuf;
 
 fn main() {
     let a = Some(1u8).map(|a| foo(a));
@@ -22,25 +36,123 @@ fn main() {
         Some(vec![1i32, 2]).map(|v| -> Box<::std::ops::Deref<Target = [i32]>> { Box::new(v) });
 }
 
-fn meta<F>(f: F) where F: Fn(u8) {
-    f(1u8)
+trait TestTrait {
+    fn trait_foo(self) -> bool;
+    fn trait_foo_ref(&self) -> bool;
+}
+
+struct TestStruct<'a> {
+    some_ref: &'a i32,
+}
+
+impl<'a> TestStruct<'a> {
+    fn foo(self) -> bool {
+        false
+    }
+    unsafe fn foo_unsafe(self) -> bool {
+        true
+    }
+}
+
+impl<'a> TestTrait for TestStruct<'a> {
+    fn trait_foo(self) -> bool {
+        false
+    }
+    fn trait_foo_ref(&self) -> bool {
+        false
+    }
+}
+
+impl<'a> std::ops::Deref for TestStruct<'a> {
+    type Target = char;
+    fn deref(&self) -> &char {
+        &'a'
+    }
+}
+
+fn test_redundant_closures_containing_method_calls() {
+    let i = 10;
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
+    let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
+    let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref());
+    let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
+    let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
+    let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
+    unsafe {
+        let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
+    }
+    let e = Some("str").map(|s| s.to_string());
+    let e = Some("str").map(str::to_string);
+    let e = Some('a').map(|s| s.to_uppercase());
+    let e = Some('a').map(char::to_uppercase);
+    let e: std::vec::Vec<usize> = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
+    let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
+    let p = Some(PathBuf::new());
+    let e = p.as_ref().and_then(|s| s.to_str());
+    let c = Some(TestStruct { some_ref: &i })
+        .as_ref()
+        .map(|c| c.to_ascii_uppercase());
+
+    fn test_different_borrow_levels<T>(t: &[&T])
+    where
+        T: TestTrait,
+    {
+        t.iter().filter(|x| x.trait_foo_ref());
+        t.iter().map(|x| x.trait_foo_ref());
+    }
+
+    let mut some = Some(|x| x * x);
+    let arr = [Ok(1), Err(2)];
+    let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect();
+}
+
+struct Thunk<T>(Box<FnMut() -> T>);
+
+impl<T> Thunk<T> {
+    fn new<F: 'static + FnOnce() -> T>(f: F) -> Thunk<T> {
+        let mut option = Some(f);
+        // This should not trigger redundant_closure (#1439)
+        Thunk(Box::new(move || option.take().unwrap()()))
+    }
+
+    fn unwrap(self) -> T {
+        let Thunk(mut f) = self;
+        f()
+    }
 }
 
-fn foo(_: u8) {
+fn foobar() {
+    let thunk = Thunk::new(|| println!("Hello, world!"));
+    thunk.unwrap()
 }
 
+fn meta<F>(f: F)
+where
+    F: Fn(u8),
+{
+    f(1u8)
+}
+
+fn foo(_: u8) {}
+
 fn foo2(_: u8) -> u8 {
     1u8
 }
 
 fn all<X, F>(x: &[X], y: &X, f: F) -> bool
-where F: Fn(&X, &X) -> bool {
+where
+    F: Fn(&X, &X) -> bool,
+{
     x.iter().all(|e| f(e, y))
 }
 
-fn below(x: &u8, y: &u8) -> bool { x < y }
+fn below(x: &u8, y: &u8) -> bool {
+    x < y
+}
 
-unsafe fn unsafe_fn(_: u8) { }
+unsafe fn unsafe_fn(_: u8) {}
 
 fn divergent(_: u8) -> ! {
     unimplemented!()
@@ -49,3 +161,19 @@ fn divergent(_: u8) -> ! {
 fn generic<T>(_: T) -> u8 {
     0
 }
+
+fn passes_fn_mut(mut x: Box<dyn FnMut()>) {
+    requires_fn_once(|| x());
+}
+fn requires_fn_once<T: FnOnce()>(_: T) {}
+
+fn test_redundant_closure_with_function_pointer() {
+    type FnPtrType = fn(u8);
+    let foo_ptr: FnPtrType = foo;
+    let a = Some(1u8).map(|a| foo_ptr(a));
+}
+
+fn test_redundant_closure_with_another_closure() {
+    let closure = |a| println!("{}", a);
+    let a = Some(1u8).map(|a| closure(a));
+}
index 5dca265c2a400c4bb2a3d01b9c5b479f80d4d5fc..ff402a1850ed868da94e81f27ab2dd74c7f48bb6 100644 (file)
@@ -1,36 +1,92 @@
 error: redundant closure found
--> $DIR/eta.rs:7:27
-  |
-7 |     let a = Some(1u8).map(|a| foo(a));
-  |                           ^^^^^^^^^^ help: remove closure as shown: `foo`
-  |
-  = note: `-D redundant-closure` implied by `-D warnings`
 --> $DIR/eta.rs:21:27
+   |
+LL |     let a = Some(1u8).map(|a| foo(a));
+   |                           ^^^^^^^^^^ help: remove closure as shown: `foo`
+   |
+   = note: `-D clippy::redundant-closure` implied by `-D warnings`
 
 error: redundant closure found
--> $DIR/eta.rs:8:10
-  |
-8 |     meta(|a| foo(a));
-  |          ^^^^^^^^^^ help: remove closure as shown: `foo`
 --> $DIR/eta.rs:22:10
+   |
+LL |     meta(|a| foo(a));
+   |          ^^^^^^^^^^ help: remove closure as shown: `foo`
 
 error: redundant closure found
--> $DIR/eta.rs:9:27
-  |
-9 |     let c = Some(1u8).map(|a| {1+2; foo}(a));
-  |                           ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `{1+2; foo}`
 --> $DIR/eta.rs:23:27
+   |
+LL |     let c = Some(1u8).map(|a| {1+2; foo}(a));
+   |                           ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `{1+2; foo}`
 
 error: this expression borrows a reference that is immediately dereferenced by the compiler
-  --> $DIR/eta.rs:11:21
+  --> $DIR/eta.rs:25:21
    |
-11 |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
+LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                     ^^^ help: change this to: `&2`
    |
-   = note: `-D needless-borrow` implied by `-D warnings`
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
 error: redundant closure found
-  --> $DIR/eta.rs:18:27
+  --> $DIR/eta.rs:32:27
    |
-18 |     let e = Some(1u8).map(|a| generic(a));
+LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: remove closure as shown: `generic`
 
-error: aborting due to 5 previous errors
+error: redundant closure found
+  --> $DIR/eta.rs:75:51
+   |
+LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
+   |                                                   ^^^^^^^^^^^ help: remove closure as shown: `TestStruct::foo`
+   |
+   = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
+
+error: redundant closure found
+  --> $DIR/eta.rs:77:51
+   |
+LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
+   |                                                   ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `TestTrait::trait_foo`
+
+error: redundant closure found
+  --> $DIR/eta.rs:80:42
+   |
+LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
+   |                                          ^^^^^^^^^^^^^ help: remove closure as shown: `std::vec::Vec::clear`
+
+error: redundant closure found
+  --> $DIR/eta.rs:85:29
+   |
+LL |     let e = Some("str").map(|s| s.to_string());
+   |                             ^^^^^^^^^^^^^^^^^ help: remove closure as shown: `std::string::ToString::to_string`
+
+error: redundant closure found
+  --> $DIR/eta.rs:87:27
+   |
+LL |     let e = Some('a').map(|s| s.to_uppercase());
+   |                           ^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_uppercase`
+
+error: redundant closure found
+  --> $DIR/eta.rs:90:65
+   |
+LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
+   |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase`
+
+error: redundant closure found
+  --> $DIR/eta.rs:108:50
+   |
+LL |     let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect();
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `some.take().unwrap()`
+
+error: redundant closure found
+  --> $DIR/eta.rs:173:27
+   |
+LL |     let a = Some(1u8).map(|a| foo_ptr(a));
+   |                           ^^^^^^^^^^^^^^ help: remove closure as shown: `foo_ptr`
+
+error: redundant closure found
+  --> $DIR/eta.rs:178:27
+   |
+LL |     let a = Some(1u8).map(|a| closure(a));
+   |                           ^^^^^^^^^^^^^^ help: remove closure as shown: `closure`
+
+error: aborting due to 14 previous errors
 
index e7ccb190d2c712a24610372d09a45f0a61883d89..d806bc6d40102e6f1efef7166d9f2ad22be0fc15 100644 (file)
-
-
-
-#[warn(eval_order_dependence)]
-#[allow(unused_assignments, unused_variables, many_single_char_names, no_effect, dead_code, blacklisted_name)]
+#[warn(clippy::eval_order_dependence)]
+#[allow(
+    unused_assignments,
+    unused_variables,
+    clippy::many_single_char_names,
+    clippy::no_effect,
+    dead_code,
+    clippy::blacklisted_name
+)]
 fn main() {
     let mut x = 0;
-    let a = { x = 1; 1 } + x;
+    let a = {
+        x = 1;
+        1
+    } + x;
 
     // Example from iss#277
-    x += { x = 20; 2 };
+    x += {
+        x = 20;
+        2
+    };
 
     // Does it work in weird places?
     // ...in the base for a struct expression?
-    struct Foo { a: i32, b: i32 };
+    struct Foo {
+        a: i32,
+        b: i32,
+    };
     let base = Foo { a: 4, b: 5 };
-    let foo = Foo { a: x, .. { x = 6; base } };
+    let foo = Foo {
+        a: x,
+        ..{
+            x = 6;
+            base
+        }
+    };
     // ...inside a closure?
     let closure = || {
         let mut x = 0;
-        x += { x = 20; 2 };
+        x += {
+            x = 20;
+            2
+        };
     };
     // ...not across a closure?
     let mut y = 0;
-    let b = (y, || { y = 1 });
+    let b = (y, || y = 1);
 
     // && and || evaluate left-to-right.
-    let a = { x = 1; true } && (x == 3);
-    let a = { x = 1; true } || (x == 3);
+    let a = {
+        x = 1;
+        true
+    } && (x == 3);
+    let a = {
+        x = 1;
+        true
+    } || (x == 3);
 
     // Make sure we don't get confused by alpha conversion.
-    let a = { let mut x = 1; x = 2; 1 } + x;
+    let a = {
+        let mut x = 1;
+        x = 2;
+        1
+    } + x;
 
     // No warning if we don't read the variable...
-    x = { x = 20; 2 };
+    x = {
+        x = 20;
+        2
+    };
     // ...if the assignment is in a closure...
-    let b = { || { x = 1; }; 1 } + x;
+    let b = {
+        || {
+            x = 1;
+        };
+        1
+    } + x;
     // ... or the access is under an address.
-    let b = ({ let p = &x; 1 }, { x = 1; x });
+    let b = (
+        {
+            let p = &x;
+            1
+        },
+        {
+            x = 1;
+            x
+        },
+    );
 
     // Limitation: l-values other than simple variables don't trigger
     // the warning.
     let mut tup = (0, 0);
-    let c = { tup.0 = 1; 1 } + tup.0;
+    let c = {
+        tup.0 = 1;
+        1
+    } + tup.0;
     // Limitation: you can get away with a read under address-of.
     let mut z = 0;
-    let b = (&{ z = x; x }, { x = 3; x });
+    let b = (
+        &{
+            z = x;
+            x
+        },
+        {
+            x = 3;
+            x
+        },
+    );
 }
index 2e01a167c01b3a9969c310e23d8d054419759748..8f4fa2228f7f4d7f7eff5594a51a23ef28116900 100644 (file)
@@ -1,51 +1,51 @@
 error: unsequenced read of a variable
- --> $DIR/eval_order_dependence.rs:8:28
-  |
-8 |     let a = { x = 1; 1 } + x;
-  |                            ^
-  |
-  = note: `-D eval-order-dependence` implied by `-D warnings`
+  --> $DIR/eval_order_dependence.rs:15:9
+   |
+LL |     } + x;
+   |         ^
+   |
+   = note: `-D clippy::eval-order-dependence` implied by `-D warnings`
 note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:8:15
-  |
-8 |     let a = { x = 1; 1 } + x;
-  |               ^^^^^
+  --> $DIR/eval_order_dependence.rs:13:9
+   |
+LL |         x = 1;
+   |         ^^^^^
 
 error: unsequenced read of a variable
-  --> $DIR/eval_order_dependence.rs:11:5
+  --> $DIR/eval_order_dependence.rs:18:5
    |
-11 |     x += { x = 20; 2 };
+LL |     x += {
    |     ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:11:12
+  --> $DIR/eval_order_dependence.rs:19:9
    |
-11 |     x += { x = 20; 2 };
-   |            ^^^^^^
+LL |         x = 20;
+   |         ^^^^^^
 
 error: unsequenced read of a variable
-  --> $DIR/eval_order_dependence.rs:17:24
+  --> $DIR/eval_order_dependence.rs:31:12
    |
-17 |     let foo = Foo { a: x, .. { x = 6; base } };
-   |                        ^
+LL |         a: x,
+   |            ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:17:32
+  --> $DIR/eval_order_dependence.rs:33:13
    |
-17 |     let foo = Foo { a: x, .. { x = 6; base } };
-   |                                ^^^^^
+LL |             x = 6;
+   |             ^^^^^
 
 error: unsequenced read of a variable
-  --> $DIR/eval_order_dependence.rs:21:9
+  --> $DIR/eval_order_dependence.rs:40:9
    |
-21 |         x += { x = 20; 2 };
+LL |         x += {
    |         ^
    |
 note: whether read occurs before this write depends on evaluation order
-  --> $DIR/eval_order_dependence.rs:21:16
+  --> $DIR/eval_order_dependence.rs:41:13
    |
-21 |         x += { x = 20; 2 };
-   |                ^^^^^^
+LL |             x = 20;
+   |             ^^^^^^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed
new file mode 100644 (file)
index 0000000..1646dff
--- /dev/null
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::excessive_precision)]
+#![allow(dead_code, unused_variables, clippy::print_literal)]
+
+fn main() {
+    // Consts
+    const GOOD32: f32 = 0.123_456;
+    const GOOD32_SM: f32 = 0.000_000_000_1;
+    const GOOD32_DOT: f32 = 10_000_000_000.0;
+    const GOOD32_EDGE: f32 = 1.000_000_8;
+    const GOOD64: f64 = 0.123_456_789_012;
+    const GOOD64_SM: f32 = 0.000_000_000_000_000_1;
+    const GOOD64_DOT: f32 = 10_000_000_000_000_000.0;
+
+    const BAD32_1: f32 = 0.123_456_79;
+    const BAD32_2: f32 = 0.123_456_79;
+    const BAD32_3: f32 = 0.1;
+    const BAD32_EDGE: f32 = 1.000_001;
+
+    const BAD64_1: f64 = 0.123_456_789_012_345_66;
+    const BAD64_2: f64 = 0.123_456_789_012_345_66;
+    const BAD64_3: f64 = 0.1;
+
+    // Literal as param
+    println!("{:?}", 8.888_888_888_888_89);
+
+    // // TODO add inferred type tests for f32
+    // Locals
+    let good32: f32 = 0.123_456_f32;
+    let good32_2: f32 = 0.123_456;
+
+    let good64: f64 = 0.123_456_789_012;
+    let good64_suf: f64 = 0.123_456_789_012f64;
+    let good64_inf = 0.123_456_789_012;
+
+    let bad32: f32 = 1.123_456_8;
+    let bad32_suf: f32 = 1.123_456_8;
+    let bad32_inf = 1.123_456_8;
+
+    let bad64: f64 = 0.123_456_789_012_345_66;
+    let bad64_suf: f64 = 0.123_456_789_012_345_66;
+    let bad64_inf = 0.123_456_789_012_345_66;
+
+    // Vectors
+    let good_vec32: Vec<f32> = vec![0.123_456];
+    let good_vec64: Vec<f64> = vec![0.123_456_789];
+
+    let bad_vec32: Vec<f32> = vec![0.123_456_79];
+    let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_78];
+
+    // Exponential float notation
+    let good_e32: f32 = 1e-10;
+    let bad_e32: f32 = 1.123_456_8e-10;
+
+    let good_bige32: f32 = 1E-10;
+    let bad_bige32: f32 = 1.123_456_8E-10;
+
+    // Inferred type
+    let good_inferred: f32 = 1f32 * 1_000_000_000.;
+
+    // issue #2840
+    let num = 0.000_000_000_01e-10f64;
+}
index 88f24d27dbc4a7d7f1e252009a961aaae2418f7f..ce4722a90f9002edd571d1d2123861905f5726c3 100644 (file)
@@ -1,6 +1,6 @@
-
-#![warn(excessive_precision)]
-#![allow(print_literal)]
+// run-rustfix
+#![warn(clippy::excessive_precision)]
+#![allow(dead_code, unused_variables, clippy::print_literal)]
 
 fn main() {
     // Consts
@@ -54,4 +54,10 @@ fn main() {
 
     let good_bige32: f32 = 1E-10;
     let bad_bige32: f32 = 1.123_456_788_888E-10;
+
+    // Inferred type
+    let good_inferred: f32 = 1f32 * 1_000_000_000.;
+
+    // issue #2840
+    let num = 0.000_000_000_01e-10f64;
 }
index 295846e9d7e011cdba69b53308e811658afc8acf..12f8a61b75c5a0f25420b142c2074c460d706c4c 100644 (file)
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:15:26
    |
-15 |     const BAD32_1: f32 = 0.123_456_789_f32;
+LL |     const BAD32_1: f32 = 0.123_456_789_f32;
    |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
    |
-   = note: `-D excessive-precision` implied by `-D warnings`
+   = note: `-D clippy::excessive-precision` implied by `-D warnings`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:16:26
    |
-16 |     const BAD32_2: f32 = 0.123_456_789;
+LL |     const BAD32_2: f32 = 0.123_456_789;
    |                          ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:17:26
    |
-17 |     const BAD32_3: f32 = 0.100_000_000_000_1;
+LL |     const BAD32_3: f32 = 0.100_000_000_000_1;
    |                          ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:18:29
    |
-18 |     const BAD32_EDGE: f32 = 1.000_000_9;
+LL |     const BAD32_EDGE: f32 = 1.000_000_9;
    |                             ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:20:26
    |
-20 |     const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
+LL |     const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:21:26
    |
-21 |     const BAD64_2: f64 = 0.123_456_789_012_345_67;
+LL |     const BAD64_2: f64 = 0.123_456_789_012_345_67;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:22:26
    |
-22 |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
+LL |     const BAD64_3: f64 = 0.100_000_000_000_000_000_1;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:25:22
    |
-25 |     println!("{:?}", 8.888_888_888_888_888_888_888);
+LL |     println!("{:?}", 8.888_888_888_888_888_888_888);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:36:22
    |
-36 |     let bad32: f32 = 1.123_456_789;
+LL |     let bad32: f32 = 1.123_456_789;
    |                      ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:37:26
    |
-37 |     let bad32_suf: f32 = 1.123_456_789_f32;
+LL |     let bad32_suf: f32 = 1.123_456_789_f32;
    |                          ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:38:21
    |
-38 |     let bad32_inf = 1.123_456_789_f32;
+LL |     let bad32_inf = 1.123_456_789_f32;
    |                     ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:40:22
    |
-40 |     let bad64: f64 = 0.123_456_789_012_345_67;
+LL |     let bad64: f64 = 0.123_456_789_012_345_67;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:41:26
    |
-41 |     let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
+LL |     let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:42:21
    |
-42 |     let bad64_inf = 0.123_456_789_012_345_67;
+LL |     let bad64_inf = 0.123_456_789_012_345_67;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:48:36
    |
-48 |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
+LL |     let bad_vec32: Vec<f32> = vec![0.123_456_789];
    |                                    ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:49:36
    |
-49 |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
+LL |     let bad_vec64: Vec<f64> = vec![0.123_456_789_123_456_789];
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:53:24
    |
-53 |     let bad_e32: f32 = 1.123_456_788_888e-10;
+LL |     let bad_e32: f32 = 1.123_456_788_888e-10;
    |                        ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10`
 
 error: float has excessive precision
   --> $DIR/excessive_precision.rs:56:27
    |
-56 |     let bad_bige32: f32 = 1.123_456_788_888E-10;
+LL |     let bad_bige32: f32 = 1.123_456_788_888E-10;
    |                           ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10`
 
 error: aborting due to 18 previous errors
diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed
new file mode 100644 (file)
index 0000000..e111ee3
--- /dev/null
@@ -0,0 +1,87 @@
+// run-rustfix
+
+#![warn(clippy::expect_fun_call)]
+
+/// Checks implementation of the `EXPECT_FUN_CALL` lint
+
+fn main() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Self {
+            Foo
+        }
+
+        fn expect(&self, msg: &str) {
+            panic!("{}", msg)
+        }
+    }
+
+    let with_some = Some("value");
+    with_some.expect("error");
+
+    let with_none: Option<i32> = None;
+    with_none.expect("error");
+
+    let error_code = 123_i32;
+    let with_none_and_format: Option<i32> = None;
+    with_none_and_format.unwrap_or_else(|| panic!("Error {}: fake error", error_code));
+
+    let with_none_and_as_str: Option<i32> = None;
+    with_none_and_as_str.unwrap_or_else(|| panic!("Error {}: fake error", error_code));
+
+    let with_ok: Result<(), ()> = Ok(());
+    with_ok.expect("error");
+
+    let with_err: Result<(), ()> = Err(());
+    with_err.expect("error");
+
+    let error_code = 123_i32;
+    let with_err_and_format: Result<(), ()> = Err(());
+    with_err_and_format.unwrap_or_else(|_| panic!("Error {}: fake error", error_code));
+
+    let with_err_and_as_str: Result<(), ()> = Err(());
+    with_err_and_as_str.unwrap_or_else(|_| panic!("Error {}: fake error", error_code));
+
+    let with_dummy_type = Foo::new();
+    with_dummy_type.expect("another test string");
+
+    let with_dummy_type_and_format = Foo::new();
+    with_dummy_type_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_dummy_type_and_as_str = Foo::new();
+    with_dummy_type_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    //Issue #2937
+    Some("foo").unwrap_or_else(|| panic!("{} {}", 1, 2));
+
+    //Issue #2979 - this should not lint
+    {
+        let msg = "bar";
+        Some("foo").expect(msg);
+    }
+
+    {
+        fn get_string() -> String {
+            "foo".to_string()
+        }
+
+        fn get_static_str() -> &'static str {
+            "foo"
+        }
+
+        fn get_non_static_str(_: &u32) -> &str {
+            "foo"
+        }
+
+        Some("foo").unwrap_or_else(|| { panic!(get_string()) });
+        Some("foo").unwrap_or_else(|| { panic!(get_string()) });
+        Some("foo").unwrap_or_else(|| { panic!(get_string()) });
+
+        Some("foo").unwrap_or_else(|| { panic!(get_static_str()) });
+        Some("foo").unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) });
+    }
+
+    //Issue #3839
+    Some(true).unwrap_or_else(|| panic!("key {}, {}", 1, 2));
+}
diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs
new file mode 100644 (file)
index 0000000..891ec88
--- /dev/null
@@ -0,0 +1,87 @@
+// run-rustfix
+
+#![warn(clippy::expect_fun_call)]
+
+/// Checks implementation of the `EXPECT_FUN_CALL` lint
+
+fn main() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Self {
+            Foo
+        }
+
+        fn expect(&self, msg: &str) {
+            panic!("{}", msg)
+        }
+    }
+
+    let with_some = Some("value");
+    with_some.expect("error");
+
+    let with_none: Option<i32> = None;
+    with_none.expect("error");
+
+    let error_code = 123_i32;
+    let with_none_and_format: Option<i32> = None;
+    with_none_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_none_and_as_str: Option<i32> = None;
+    with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    let with_ok: Result<(), ()> = Ok(());
+    with_ok.expect("error");
+
+    let with_err: Result<(), ()> = Err(());
+    with_err.expect("error");
+
+    let error_code = 123_i32;
+    let with_err_and_format: Result<(), ()> = Err(());
+    with_err_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_err_and_as_str: Result<(), ()> = Err(());
+    with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    let with_dummy_type = Foo::new();
+    with_dummy_type.expect("another test string");
+
+    let with_dummy_type_and_format = Foo::new();
+    with_dummy_type_and_format.expect(&format!("Error {}: fake error", error_code));
+
+    let with_dummy_type_and_as_str = Foo::new();
+    with_dummy_type_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+
+    //Issue #2937
+    Some("foo").expect(format!("{} {}", 1, 2).as_ref());
+
+    //Issue #2979 - this should not lint
+    {
+        let msg = "bar";
+        Some("foo").expect(msg);
+    }
+
+    {
+        fn get_string() -> String {
+            "foo".to_string()
+        }
+
+        fn get_static_str() -> &'static str {
+            "foo"
+        }
+
+        fn get_non_static_str(_: &u32) -> &str {
+            "foo"
+        }
+
+        Some("foo").expect(&get_string());
+        Some("foo").expect(get_string().as_ref());
+        Some("foo").expect(get_string().as_str());
+
+        Some("foo").expect(get_static_str());
+        Some("foo").expect(get_non_static_str(&0));
+    }
+
+    //Issue #3839
+    Some(true).expect(&format!("key {}, {}", 1, 2));
+}
diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr
new file mode 100644 (file)
index 0000000..bb16fab
--- /dev/null
@@ -0,0 +1,70 @@
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:28:26
+   |
+LL |     with_none_and_format.expect(&format!("Error {}: fake error", error_code));
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
+   |
+   = note: `-D clippy::expect-fun-call` implied by `-D warnings`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:31:26
+   |
+LL |     with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:41:25
+   |
+LL |     with_err_and_format.expect(&format!("Error {}: fake error", error_code));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:44:25
+   |
+LL |     with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:56:17
+   |
+LL |     Some("foo").expect(format!("{} {}", 1, 2).as_ref());
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:77:21
+   |
+LL |         Some("foo").expect(&get_string());
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:78:21
+   |
+LL |         Some("foo").expect(get_string().as_ref());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:79:21
+   |
+LL |         Some("foo").expect(get_string().as_str());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:81:21
+   |
+LL |         Some("foo").expect(get_static_str());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_static_str()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:82:21
+   |
+LL |         Some("foo").expect(get_non_static_str(&0));
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) })`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:86:16
+   |
+LL |     Some(true).expect(&format!("key {}, {}", 1, 2));
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs
new file mode 100644 (file)
index 0000000..71ef1e8
--- /dev/null
@@ -0,0 +1,124 @@
+#![warn(clippy::explicit_counter_loop)]
+
+fn main() {
+    let mut vec = vec![1, 2, 3, 4];
+    let mut _index = 0;
+    for _v in &vec {
+        _index += 1
+    }
+
+    let mut _index = 1;
+    _index = 0;
+    for _v in &vec {
+        _index += 1
+    }
+}
+
+mod issue_1219 {
+    pub fn test() {
+        // should not trigger the lint because variable is used after the loop #473
+        let vec = vec![1, 2, 3];
+        let mut index = 0;
+        for _v in &vec {
+            index += 1
+        }
+        println!("index: {}", index);
+
+        // should not trigger the lint because the count is conditional #1219
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            if ch == 'a' {
+                continue;
+            }
+            count += 1;
+            println!("{}", count);
+        }
+
+        // should not trigger the lint because the count is conditional
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            if ch == 'a' {
+                count += 1;
+            }
+            println!("{}", count);
+        }
+
+        // should trigger the lint because the count is not conditional
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            count += 1;
+            if ch == 'a' {
+                continue;
+            }
+            println!("{}", count);
+        }
+
+        // should trigger the lint because the count is not conditional
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            count += 1;
+            for i in 0..2 {
+                let _ = 123;
+            }
+            println!("{}", count);
+        }
+
+        // should not trigger the lint because the count is incremented multiple times
+        let text = "banana";
+        let mut count = 0;
+        for ch in text.chars() {
+            count += 1;
+            for i in 0..2 {
+                count += 1;
+            }
+            println!("{}", count);
+        }
+    }
+}
+
+mod issue_3308 {
+    pub fn test() {
+        // should not trigger the lint because the count is incremented multiple times
+        let mut skips = 0;
+        let erasures = vec![];
+        for i in 0..10 {
+            while erasures.contains(&(i + skips)) {
+                skips += 1;
+            }
+            println!("{}", skips);
+        }
+
+        // should not trigger the lint because the count is incremented multiple times
+        let mut skips = 0;
+        for i in 0..10 {
+            let mut j = 0;
+            while j < 5 {
+                skips += 1;
+                j += 1;
+            }
+            println!("{}", skips);
+        }
+
+        // should not trigger the lint because the count is incremented multiple times
+        let mut skips = 0;
+        for i in 0..10 {
+            for j in 0..5 {
+                skips += 1;
+            }
+            println!("{}", skips);
+        }
+    }
+}
+
+mod issue_1670 {
+    pub fn test() {
+        let mut count = 0;
+        for _i in 3..10 {
+            count += 1;
+        }
+    }
+}
diff --git a/tests/ui/explicit_counter_loop.stderr b/tests/ui/explicit_counter_loop.stderr
new file mode 100644 (file)
index 0000000..5efd51a
--- /dev/null
@@ -0,0 +1,34 @@
+error: the variable `_index` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:6:15
+   |
+LL |     for _v in &vec {
+   |               ^^^^ help: consider using: `for (_index, _v) in (&vec).enumerate()`
+   |
+   = note: `-D clippy::explicit-counter-loop` implied by `-D warnings`
+
+error: the variable `_index` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:12:15
+   |
+LL |     for _v in &vec {
+   |               ^^^^ help: consider using: `for (_index, _v) in (&vec).enumerate()`
+
+error: the variable `count` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:51:19
+   |
+LL |         for ch in text.chars() {
+   |                   ^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()`
+
+error: the variable `count` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:62:19
+   |
+LL |         for ch in text.chars() {
+   |                   ^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()`
+
+error: the variable `count` is used as a loop counter.
+  --> $DIR/explicit_counter_loop.rs:120:19
+   |
+LL |         for _i in 3..10 {
+   |                   ^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/explicit_write.fixed b/tests/ui/explicit_write.fixed
new file mode 100644 (file)
index 0000000..692d2ca
--- /dev/null
@@ -0,0 +1,51 @@
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(clippy::explicit_write)]
+
+fn stdout() -> String {
+    String::new()
+}
+
+fn stderr() -> String {
+    String::new()
+}
+
+fn main() {
+    // these should warn
+    {
+        use std::io::Write;
+        print!("test");
+        eprint!("test");
+        println!("test");
+        eprintln!("test");
+        print!("test");
+        eprint!("test");
+
+        // including newlines
+        println!("test\ntest");
+        eprintln!("test\ntest");
+    }
+    // these should not warn, different destination
+    {
+        use std::fmt::Write;
+        let mut s = String::new();
+        write!(s, "test").unwrap();
+        write!(s, "test").unwrap();
+        writeln!(s, "test").unwrap();
+        writeln!(s, "test").unwrap();
+        s.write_fmt(format_args!("test")).unwrap();
+        s.write_fmt(format_args!("test")).unwrap();
+        write!(stdout(), "test").unwrap();
+        write!(stderr(), "test").unwrap();
+        writeln!(stdout(), "test").unwrap();
+        writeln!(stderr(), "test").unwrap();
+        stdout().write_fmt(format_args!("test")).unwrap();
+        stderr().write_fmt(format_args!("test")).unwrap();
+    }
+    // these should not warn, no unwrap
+    {
+        use std::io::Write;
+        std::io::stdout().write_fmt(format_args!("test")).expect("no stdout");
+        std::io::stderr().write_fmt(format_args!("test")).expect("no stderr");
+    }
+}
index 71992123ceb6070c32943800d3d6ab6a46ffa61d..455c5ef55d05c4209be525017565edc7706f26be 100644 (file)
@@ -1,5 +1,6 @@
-#![warn(explicit_write)]
-
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(clippy::explicit_write)]
 
 fn stdout() -> String {
     String::new()
@@ -19,6 +20,10 @@ fn main() {
         writeln!(std::io::stderr(), "test").unwrap();
         std::io::stdout().write_fmt(format_args!("test")).unwrap();
         std::io::stderr().write_fmt(format_args!("test")).unwrap();
+
+        // including newlines
+        writeln!(std::io::stdout(), "test\ntest").unwrap();
+        writeln!(std::io::stderr(), "test\ntest").unwrap();
     }
     // these should not warn, different destination
     {
index 7a2a0c66f2378e8be9d954f1ce8c4677db2cccf1..9feef9c0dc8443cb0ef33f4df01e59a9110bea1c 100644 (file)
@@ -1,40 +1,52 @@
-error: use of `write!(stdout(), ...).unwrap()`. Consider using `print!` instead
-  --> $DIR/explicit_write.rs:16:9
-   |
-16 |         write!(std::io::stdout(), "test").unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D explicit-write` implied by `-D warnings`
-
-error: use of `write!(stderr(), ...).unwrap()`. Consider using `eprint!` instead
+error: use of `write!(stdout(), ...).unwrap()`
   --> $DIR/explicit_write.rs:17:9
    |
-17 |         write!(std::io::stderr(), "test").unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         write!(std::io::stdout(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
+   |
+   = note: `-D clippy::explicit-write` implied by `-D warnings`
 
-error: use of `writeln!(stdout(), ...).unwrap()`. Consider using `println!` instead
+error: use of `write!(stderr(), ...).unwrap()`
   --> $DIR/explicit_write.rs:18:9
    |
-18 |         writeln!(std::io::stdout(), "test").unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         write!(std::io::stderr(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
 
-error: use of `writeln!(stderr(), ...).unwrap()`. Consider using `eprintln!` instead
+error: use of `writeln!(stdout(), ...).unwrap()`
   --> $DIR/explicit_write.rs:19:9
    |
-19 |         writeln!(std::io::stderr(), "test").unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         writeln!(std::io::stdout(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")`
 
-error: use of `stdout().write_fmt(...).unwrap()`. Consider using `print!` instead
+error: use of `writeln!(stderr(), ...).unwrap()`
   --> $DIR/explicit_write.rs:20:9
    |
-20 |         std::io::stdout().write_fmt(format_args!("test")).unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         writeln!(std::io::stderr(), "test").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")`
 
-error: use of `stderr().write_fmt(...).unwrap()`. Consider using `eprint!` instead
+error: use of `stdout().write_fmt(...).unwrap()`
   --> $DIR/explicit_write.rs:21:9
    |
-21 |         std::io::stderr().write_fmt(format_args!("test")).unwrap();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         std::io::stdout().write_fmt(format_args!("test")).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
+
+error: use of `stderr().write_fmt(...).unwrap()`
+  --> $DIR/explicit_write.rs:22:9
+   |
+LL |         std::io::stderr().write_fmt(format_args!("test")).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
+
+error: use of `writeln!(stdout(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:25:9
+   |
+LL |         writeln!(std::io::stdout(), "test/ntest").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:26:9
+   |
+LL |         writeln!(std::io::stderr(), "test/ntest").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")`
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
index db11891907130fa01c980e1b2f1629e781b84116..679f4a7dc357d4a182be13c9a292d43ac229ea5c 100644 (file)
@@ -1,4 +1,4 @@
-#![deny(fallible_impl_from)]
+#![deny(clippy::fallible_impl_from)]
 
 // docs example
 struct Foo(i32);
@@ -8,7 +8,6 @@ fn from(s: String) -> Self {
     }
 }
 
-
 struct Valid(Vec<u8>);
 
 impl<'a> From<&'a str> for Valid {
@@ -22,7 +21,6 @@ fn from(i: usize) -> Valid {
     }
 }
 
-
 struct Invalid;
 
 impl From<usize> for Invalid {
index c8af77ecab3c4543b90f87f3a4e858b1ebf5b970..8b847df65cda246c99eb26c34124891a15c57242 100644 (file)
@@ -1,91 +1,91 @@
 error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:5:1
-  |
-5 | / impl From<String> for Foo {
-6 | |     fn from(s: String) -> Self {
-7 | |         Foo(s.parse().unwrap())
-8 | |     }
-9 | | }
-  | |_^
-  |
 --> $DIR/fallible_impl_from.rs:5:1
+   |
+LL | / impl From<String> for Foo {
+LL | |     fn from(s: String) -> Self {
+LL | |         Foo(s.parse().unwrap())
+LL | |     }
+LL | | }
+   | |_^
+   |
 note: lint level defined here
- --> $DIR/fallible_impl_from.rs:1:9
-  |
-1 | #![deny(fallible_impl_from)]
-  |         ^^^^^^^^^^^^^^^^^^
-  = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
 --> $DIR/fallible_impl_from.rs:1:9
+   |
+LL | #![deny(clippy::fallible_impl_from)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
 note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:7:13
-  |
-7 |         Foo(s.parse().unwrap())
-  |             ^^^^^^^^^^^^^^^^^^
 --> $DIR/fallible_impl_from.rs:7:13
+   |
+LL |         Foo(s.parse().unwrap())
+   |             ^^^^^^^^^^^^^^^^^^
 
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:28:1
+  --> $DIR/fallible_impl_from.rs:26:1
    |
-28 | / impl From<usize> for Invalid {
-29 | |     fn from(i: usize) -> Invalid {
-30 | |         if i != 42 {
-31 | |             panic!();
+LL | / impl From<usize> for Invalid {
+LL | |     fn from(i: usize) -> Invalid {
+LL | |         if i != 42 {
+LL | |             panic!();
 ...  |
-34 | |     }
-35 | | }
+LL | |     }
+LL | | }
    | |_^
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:31:13
+  --> $DIR/fallible_impl_from.rs:29:13
    |
-31 |             panic!();
+LL |             panic!();
    |             ^^^^^^^^^
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:37:1
+  --> $DIR/fallible_impl_from.rs:35:1
    |
-37 | / impl From<Option<String>> for Invalid {
-38 | |     fn from(s: Option<String>) -> Invalid {
-39 | |         let s = s.unwrap();
-40 | |         if !s.is_empty() {
+LL | / impl From<Option<String>> for Invalid {
+LL | |     fn from(s: Option<String>) -> Invalid {
+LL | |         let s = s.unwrap();
+LL | |         if !s.is_empty() {
 ...  |
-46 | |     }
-47 | | }
+LL | |     }
+LL | | }
    | |_^
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:39:17
+  --> $DIR/fallible_impl_from.rs:37:17
    |
-39 |         let s = s.unwrap();
+LL |         let s = s.unwrap();
    |                 ^^^^^^^^^^
-40 |         if !s.is_empty() {
-41 |             panic!(42);
+LL |         if !s.is_empty() {
+LL |             panic!(42);
    |             ^^^^^^^^^^^
-42 |         } else if s.parse::<u32>().unwrap() != 42 {
+LL |         } else if s.parse::<u32>().unwrap() != 42 {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
-43 |             panic!("{:?}", s);
+LL |             panic!("{:?}", s);
    |             ^^^^^^^^^^^^^^^^^^
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: consider implementing `TryFrom` instead
-  --> $DIR/fallible_impl_from.rs:55:1
+  --> $DIR/fallible_impl_from.rs:53:1
    |
-55 | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
-56 | |     fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
-57 | |         if s.parse::<u32>().ok().unwrap() != 42 {
-58 | |             panic!("{:?}", s);
+LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
+LL | |     fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
+LL | |         if s.parse::<u32>().ok().unwrap() != 42 {
+LL | |             panic!("{:?}", s);
 ...  |
-61 | |     }
-62 | | }
+LL | |     }
+LL | | }
    | |_^
    |
    = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail.
 note: potential failure(s)
-  --> $DIR/fallible_impl_from.rs:57:12
+  --> $DIR/fallible_impl_from.rs:55:12
    |
-57 |         if s.parse::<u32>().ok().unwrap() != 42 {
+LL |         if s.parse::<u32>().ok().unwrap() != 42 {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-58 |             panic!("{:?}", s);
+LL |             panic!("{:?}", s);
    |             ^^^^^^^^^^^^^^^^^^
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
diff --git a/tests/ui/filter_map_next.rs b/tests/ui/filter_map_next.rs
new file mode 100644 (file)
index 0000000..f5d051b
--- /dev/null
@@ -0,0 +1,20 @@
+#![warn(clippy::all, clippy::pedantic)]
+
+fn main() {
+    let a = ["1", "lol", "3", "NaN", "5"];
+
+    let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+    assert_eq!(element, Some(1));
+
+    #[rustfmt::skip]
+    let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
+        .into_iter()
+        .filter_map(|x| {
+            if x == 2 {
+                Some(x * 2)
+            } else {
+                None
+            }
+        })
+        .next();
+}
diff --git a/tests/ui/filter_map_next.stderr b/tests/ui/filter_map_next.stderr
new file mode 100644 (file)
index 0000000..d69ae21
--- /dev/null
@@ -0,0 +1,24 @@
+error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead.
+  --> $DIR/filter_map_next.rs:6:32
+   |
+LL |     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::filter-map-next` implied by `-D warnings`
+   = note: replace `filter_map(|s| s.parse().ok()).next()` with `find_map(|s| s.parse().ok())`
+
+error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead.
+  --> $DIR/filter_map_next.rs:10:26
+   |
+LL |       let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
+   |  __________________________^
+LL | |         .into_iter()
+LL | |         .filter_map(|x| {
+LL | |             if x == 2 {
+...  |
+LL | |         })
+LL | |         .next();
+   | |_______________^
+
+error: aborting due to 2 previous errors
+
index 29230c48ea3ed3876b8589b21f30e1a6760938fd..ef434245fd70c6c6721e5f67d9875f2cd0169cb4 100644 (file)
@@ -1,27 +1,24 @@
-
-
-
-#![warn(clippy, clippy_pedantic)]
-#![allow(missing_docs_in_private_items)]
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::missing_docs_in_private_items)]
 
 fn main() {
-    let _: Vec<_> = vec![5; 6].into_iter()
-                              .filter(|&x| x == 0)
-                              .map(|x| x * 2)
-                              .collect();
+    let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
 
-    let _: Vec<_> = vec![5_i8; 6].into_iter()
-                                .filter(|&x| x == 0)
-                                .flat_map(|x| x.checked_mul(2))
-                                .collect();
+    let _: Vec<_> = vec![5_i8; 6]
+        .into_iter()
+        .filter(|&x| x == 0)
+        .flat_map(|x| x.checked_mul(2))
+        .collect();
 
-    let _: Vec<_> = vec![5_i8; 6].into_iter()
-                                .filter_map(|x| x.checked_mul(2))
-                                .flat_map(|x| x.checked_mul(2))
-                                .collect();
+    let _: Vec<_> = vec![5_i8; 6]
+        .into_iter()
+        .filter_map(|x| x.checked_mul(2))
+        .flat_map(|x| x.checked_mul(2))
+        .collect();
 
-    let _: Vec<_> = vec![5_i8; 6].into_iter()
-                                .filter_map(|x| x.checked_mul(2))
-                                .map(|x| x.checked_mul(2))
-                                .collect();
+    let _: Vec<_> = vec![5_i8; 6]
+        .into_iter()
+        .filter_map(|x| x.checked_mul(2))
+        .map(|x| x.checked_mul(2))
+        .collect();
 }
index cec03a47bfdebfd8cd0dc939fff6e01865b4201c..9dfd91f6d6409c6ab0275afbfe75631e0a8c1302 100644 (file)
@@ -1,40 +1,40 @@
 error: called `filter(p).map(q)` on an `Iterator`. This is more succinctly expressed by calling `.filter_map(..)` instead.
-  --> $DIR/filter_methods.rs:8:21
+  --> $DIR/filter_methods.rs:5:21
    |
-8  |       let _: Vec<_> = vec![5; 6].into_iter()
-   |  _____________________^
-9  | |                               .filter(|&x| x == 0)
-10 | |                               .map(|x| x * 2)
-   | |_____________________________________________^
+LL |     let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D filter-map` implied by `-D warnings`
+   = note: `-D clippy::filter-map` implied by `-D warnings`
 
 error: called `filter(p).flat_map(q)` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` and filtering by returning an empty Iterator.
-  --> $DIR/filter_methods.rs:13:21
+  --> $DIR/filter_methods.rs:7:21
    |
-13 |       let _: Vec<_> = vec![5_i8; 6].into_iter()
+LL |       let _: Vec<_> = vec![5_i8; 6]
    |  _____________________^
-14 | |                                 .filter(|&x| x == 0)
-15 | |                                 .flat_map(|x| x.checked_mul(2))
-   | |_______________________________________________________________^
+LL | |         .into_iter()
+LL | |         .filter(|&x| x == 0)
+LL | |         .flat_map(|x| x.checked_mul(2))
+   | |_______________________________________^
 
 error: called `filter_map(p).flat_map(q)` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)` and filtering by returning an empty Iterator.
-  --> $DIR/filter_methods.rs:18:21
+  --> $DIR/filter_methods.rs:13:21
    |
-18 |       let _: Vec<_> = vec![5_i8; 6].into_iter()
+LL |       let _: Vec<_> = vec![5_i8; 6]
    |  _____________________^
-19 | |                                 .filter_map(|x| x.checked_mul(2))
-20 | |                                 .flat_map(|x| x.checked_mul(2))
-   | |_______________________________________________________________^
+LL | |         .into_iter()
+LL | |         .filter_map(|x| x.checked_mul(2))
+LL | |         .flat_map(|x| x.checked_mul(2))
+   | |_______________________________________^
 
 error: called `filter_map(p).map(q)` on an `Iterator`. This is more succinctly expressed by only calling `.filter_map(..)` instead.
-  --> $DIR/filter_methods.rs:23:21
+  --> $DIR/filter_methods.rs:19:21
    |
-23 |       let _: Vec<_> = vec![5_i8; 6].into_iter()
+LL |       let _: Vec<_> = vec![5_i8; 6]
    |  _____________________^
-24 | |                                 .filter_map(|x| x.checked_mul(2))
-25 | |                                 .map(|x| x.checked_mul(2))
-   | |__________________________________________________________^
+LL | |         .into_iter()
+LL | |         .filter_map(|x| x.checked_mul(2))
+LL | |         .map(|x| x.checked_mul(2))
+   | |__________________________________^
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/find_map.rs b/tests/ui/find_map.rs
new file mode 100644 (file)
index 0000000..c28cca1
--- /dev/null
@@ -0,0 +1,32 @@
+#![warn(clippy::all, clippy::pedantic)]
+
+#[derive(Debug, Copy, Clone)]
+enum Flavor {
+    Chocolate,
+}
+
+#[derive(Debug, Copy, Clone)]
+enum Dessert {
+    Banana,
+    Pudding,
+    Cake(Flavor),
+}
+
+fn main() {
+    let desserts_of_the_week = vec![Dessert::Banana, Dessert::Cake(Flavor::Chocolate), Dessert::Pudding];
+
+    let a = ["lol", "NaN", "2", "5", "Xunda"];
+
+    let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
+
+    let _: Option<Flavor> = desserts_of_the_week
+        .iter()
+        .find(|dessert| match *dessert {
+            Dessert::Cake(_) => true,
+            _ => false,
+        })
+        .map(|dessert| match *dessert {
+            Dessert::Cake(ref flavor) => *flavor,
+            _ => unreachable!(),
+        });
+}
diff --git a/tests/ui/find_map.stderr b/tests/ui/find_map.stderr
new file mode 100644 (file)
index 0000000..0417c7f
--- /dev/null
@@ -0,0 +1,23 @@
+error: called `find(p).map(q)` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead.
+  --> $DIR/find_map.rs:20:26
+   |
+LL |     let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::find-map` implied by `-D warnings`
+
+error: called `find(p).map(q)` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead.
+  --> $DIR/find_map.rs:22:29
+   |
+LL |       let _: Option<Flavor> = desserts_of_the_week
+   |  _____________________________^
+LL | |         .iter()
+LL | |         .find(|dessert| match *dessert {
+LL | |             Dessert::Cake(_) => true,
+...  |
+LL | |             _ => unreachable!(),
+LL | |         });
+   | |__________^
+
+error: aborting due to 2 previous errors
+
index 9dd9ea9b04d557932fa79eab5400f350fc038ac8..92d38527bbf1b5de2b12c62f627a884aeaf9a9c8 100644 (file)
@@ -1,27 +1,38 @@
-
-
-
-#![warn(float_cmp)]
-#![allow(unused, no_effect, unnecessary_operation, cast_lossless)]
+#![warn(clippy::float_cmp)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
 
 use std::ops::Add;
 
-const ZERO : f32 = 0.0;
-const ONE : f32 = ZERO + 1.0;
+const ZERO: f32 = 0.0;
+const ONE: f32 = ZERO + 1.0;
 
-fn twice<T>(x : T) -> T where T : Add<T, Output = T>, T : Copy {
+fn twice<T>(x: T) -> T
+where
+    T: Add<T, Output = T>,
+    T: Copy,
+{
     x + x
 }
 
 fn eq_fl(x: f32, y: f32) -> bool {
-    if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn
+    if x.is_nan() {
+        y.is_nan()
+    } else {
+        x == y
+    } // no error, inside "eq" fn
 }
 
 fn fl_eq(x: f32, y: f32) -> bool {
-    if x.is_nan() { y.is_nan() } else { x == y } // no error, inside "eq" fn
+    if x.is_nan() {
+        y.is_nan()
+    } else {
+        x == y
+    } // no error, inside "eq" fn
 }
 
-struct X { val: f32 }
+struct X {
+    val: f32,
+}
 
 impl PartialEq for X {
     fn eq(&self, o: &X) -> bool {
@@ -49,7 +60,7 @@ fn main() {
     ONE as f64 != 2.0;
     ONE as f64 != 0.0; // no error, comparison with zero is ok
 
-    let x : f64 = 1.0;
+    let x: f64 = 1.0;
 
     x == 1.0;
     x != 0f64; // no error, comparison with zero is ok
@@ -61,7 +72,7 @@ fn main() {
     x <= 0.0;
     x >= 0.0;
 
-    let xs : [f32; 1] = [0.0];
+    let xs: [f32; 1] = [0.0];
     let a: *const f32 = xs.as_ptr();
     let b: *const f32 = xs.as_ptr();
 
index df404a1eec3f00a2d9b4803a86ad78b097f7c4f9..ddaf4b82497c01e3c58589319f0da12be68ef188 100644 (file)
@@ -1,38 +1,38 @@
 error: strict comparison of f32 or f64
-  --> $DIR/float_cmp.rs:49:5
+  --> $DIR/float_cmp.rs:60:5
    |
-49 |     ONE as f64 != 2.0;
+LL |     ONE as f64 != 2.0;
    |     ^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE as f64 - 2.0).abs() < error`
    |
-   = note: `-D float-cmp` implied by `-D warnings`
+   = note: `-D clippy::float-cmp` implied by `-D warnings`
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp.rs:49:5
+  --> $DIR/float_cmp.rs:60:5
    |
-49 |     ONE as f64 != 2.0;
+LL |     ONE as f64 != 2.0;
    |     ^^^^^^^^^^^^^^^^^
 
 error: strict comparison of f32 or f64
-  --> $DIR/float_cmp.rs:54:5
+  --> $DIR/float_cmp.rs:65:5
    |
-54 |     x == 1.0;
+LL |     x == 1.0;
    |     ^^^^^^^^ help: consider comparing them within some error: `(x - 1.0).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp.rs:54:5
+  --> $DIR/float_cmp.rs:65:5
    |
-54 |     x == 1.0;
+LL |     x == 1.0;
    |     ^^^^^^^^
 
 error: strict comparison of f32 or f64
-  --> $DIR/float_cmp.rs:57:5
+  --> $DIR/float_cmp.rs:68:5
    |
-57 |     twice(x) != twice(ONE as f64);
+LL |     twice(x) != twice(ONE as f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(twice(x) - twice(ONE as f64)).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp.rs:57:5
+  --> $DIR/float_cmp.rs:68:5
    |
-57 |     twice(x) != twice(ONE as f64);
+LL |     twice(x) != twice(ONE as f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
index adf2ab70368a901aac30c614e7f43f74eac75cbd..17ad274bd6dffb8a58ca33dc66aac748b176ac45 100644 (file)
@@ -1,15 +1,16 @@
-
-
-
-#![warn(float_cmp_const)]
-#![allow(float_cmp)]
-#![allow(unused, no_effect, unnecessary_operation)]
+#![warn(clippy::float_cmp_const)]
+#![allow(clippy::float_cmp)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 
 const ONE: f32 = 1.0;
 const TWO: f32 = 2.0;
 
 fn eq_one(x: f32) -> bool {
-    if x.is_nan() { false } else { x == ONE } // no error, inside "eq" fn
+    if x.is_nan() {
+        false
+    } else {
+        x == ONE
+    } // no error, inside "eq" fn
 }
 
 fn main() {
@@ -18,7 +19,8 @@ fn main() {
     TWO == ONE;
     TWO != ONE;
     ONE + ONE == TWO;
-    1 as f32 == ONE;
+    let x = 1;
+    x as f32 == ONE;
 
     let v = 0.9;
     v == ONE;
@@ -36,7 +38,7 @@ fn main() {
     ONE != ::std::f32::INFINITY;
     ONE == ::std::f32::NEG_INFINITY;
 
-    // no errors, but will warn float_cmp if '#![allow(float_cmp)]' above is removed
+    // no errors, but will warn clippy::float_cmp if '#![allow(float_cmp)]' above is removed
     let w = 1.1;
     v == w;
     v != w;
index 6367ec73c963083b41f7181c8f7cf869c020da4a..0c746e24d12482100cdba1326622217cd624dfe3 100644 (file)
@@ -1,86 +1,86 @@
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:17:5
+  --> $DIR/float_cmp_const.rs:18:5
    |
-17 |     1f32 == ONE;
+LL |     1f32 == ONE;
    |     ^^^^^^^^^^^ help: consider comparing them within some error: `(1f32 - ONE).abs() < error`
    |
-   = note: `-D float-cmp-const` implied by `-D warnings`
+   = note: `-D clippy::float-cmp-const` implied by `-D warnings`
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:17:5
+  --> $DIR/float_cmp_const.rs:18:5
    |
-17 |     1f32 == ONE;
+LL |     1f32 == ONE;
    |     ^^^^^^^^^^^
 
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:18:5
+  --> $DIR/float_cmp_const.rs:19:5
    |
-18 |     TWO == ONE;
+LL |     TWO == ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:18:5
+  --> $DIR/float_cmp_const.rs:19:5
    |
-18 |     TWO == ONE;
+LL |     TWO == ONE;
    |     ^^^^^^^^^^
 
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:19:5
+  --> $DIR/float_cmp_const.rs:20:5
    |
-19 |     TWO != ONE;
+LL |     TWO != ONE;
    |     ^^^^^^^^^^ help: consider comparing them within some error: `(TWO - ONE).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:19:5
+  --> $DIR/float_cmp_const.rs:20:5
    |
-19 |     TWO != ONE;
+LL |     TWO != ONE;
    |     ^^^^^^^^^^
 
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:20:5
+  --> $DIR/float_cmp_const.rs:21:5
    |
-20 |     ONE + ONE == TWO;
+LL |     ONE + ONE == TWO;
    |     ^^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(ONE + ONE - TWO).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:20:5
+  --> $DIR/float_cmp_const.rs:21:5
    |
-20 |     ONE + ONE == TWO;
+LL |     ONE + ONE == TWO;
    |     ^^^^^^^^^^^^^^^^
 
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:21:5
+  --> $DIR/float_cmp_const.rs:23:5
    |
-21 |     1 as f32 == ONE;
-   |     ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(1 as f32 - ONE).abs() < error`
+LL |     x as f32 == ONE;
+   |     ^^^^^^^^^^^^^^^ help: consider comparing them within some error: `(x as f32 - ONE).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:21:5
+  --> $DIR/float_cmp_const.rs:23:5
    |
-21 |     1 as f32 == ONE;
+LL |     x as f32 == ONE;
    |     ^^^^^^^^^^^^^^^
 
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:24:5
+  --> $DIR/float_cmp_const.rs:26:5
    |
-24 |     v == ONE;
+LL |     v == ONE;
    |     ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:24:5
+  --> $DIR/float_cmp_const.rs:26:5
    |
-24 |     v == ONE;
+LL |     v == ONE;
    |     ^^^^^^^^
 
 error: strict comparison of f32 or f64 constant
-  --> $DIR/float_cmp_const.rs:25:5
+  --> $DIR/float_cmp_const.rs:27:5
    |
-25 |     v != ONE;
+LL |     v != ONE;
    |     ^^^^^^^^ help: consider comparing them within some error: `(v - ONE).abs() < error`
    |
 note: std::f32::EPSILON and std::f64::EPSILON are available.
-  --> $DIR/float_cmp_const.rs:25:5
+  --> $DIR/float_cmp_const.rs:27:5
    |
-25 |     v != ONE;
+LL |     v != ONE;
    |     ^^^^^^^^
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/fn_to_numeric_cast.rs b/tests/ui/fn_to_numeric_cast.rs
new file mode 100644 (file)
index 0000000..21573af
--- /dev/null
@@ -0,0 +1,55 @@
+// only-64bit
+
+#![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
+
+fn foo() -> String {
+    String::new()
+}
+
+fn test_function_to_numeric_cast() {
+    let _ = foo as i8;
+    let _ = foo as i16;
+    let _ = foo as i32;
+    let _ = foo as i64;
+    let _ = foo as i128;
+    let _ = foo as isize;
+
+    let _ = foo as u8;
+    let _ = foo as u16;
+    let _ = foo as u32;
+    let _ = foo as u64;
+    let _ = foo as u128;
+
+    // Casting to usize is OK and should not warn
+    let _ = foo as usize;
+
+    // Cast `f` (a `FnDef`) to `fn()` should not warn
+    fn f() {}
+    let _ = f as fn();
+}
+
+fn test_function_var_to_numeric_cast() {
+    let abc: fn() -> String = foo;
+
+    let _ = abc as i8;
+    let _ = abc as i16;
+    let _ = abc as i32;
+    let _ = abc as i64;
+    let _ = abc as i128;
+    let _ = abc as isize;
+
+    let _ = abc as u8;
+    let _ = abc as u16;
+    let _ = abc as u32;
+    let _ = abc as u64;
+    let _ = abc as u128;
+
+    // Casting to usize is OK and should not warn
+    let _ = abc as usize;
+}
+
+fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
+    f as i32
+}
+
+fn main() {}
diff --git a/tests/ui/fn_to_numeric_cast.stderr b/tests/ui/fn_to_numeric_cast.stderr
new file mode 100644 (file)
index 0000000..e9549e1
--- /dev/null
@@ -0,0 +1,144 @@
+error: casting function pointer `foo` to `i8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:10:13
+   |
+LL |     let _ = foo as i8;
+   |             ^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:11:13
+   |
+LL |     let _ = foo as i16;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `i32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:12:13
+   |
+LL |     let _ = foo as i32;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `i64`
+  --> $DIR/fn_to_numeric_cast.rs:13:13
+   |
+LL |     let _ = foo as i64;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+   |
+   = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i128`
+  --> $DIR/fn_to_numeric_cast.rs:14:13
+   |
+LL |     let _ = foo as i128;
+   |             ^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `isize`
+  --> $DIR/fn_to_numeric_cast.rs:15:13
+   |
+LL |     let _ = foo as isize;
+   |             ^^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:17:13
+   |
+LL |     let _ = foo as u8;
+   |             ^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:18:13
+   |
+LL |     let _ = foo as u16;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:19:13
+   |
+LL |     let _ = foo as u32;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u64`
+  --> $DIR/fn_to_numeric_cast.rs:20:13
+   |
+LL |     let _ = foo as u64;
+   |             ^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `foo` to `u128`
+  --> $DIR/fn_to_numeric_cast.rs:21:13
+   |
+LL |     let _ = foo as u128;
+   |             ^^^^^^^^^^^ help: try: `foo as usize`
+
+error: casting function pointer `abc` to `i8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:34:13
+   |
+LL |     let _ = abc as i8;
+   |             ^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:35:13
+   |
+LL |     let _ = abc as i16;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:36:13
+   |
+LL |     let _ = abc as i32;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i64`
+  --> $DIR/fn_to_numeric_cast.rs:37:13
+   |
+LL |     let _ = abc as i64;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `i128`
+  --> $DIR/fn_to_numeric_cast.rs:38:13
+   |
+LL |     let _ = abc as i128;
+   |             ^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `isize`
+  --> $DIR/fn_to_numeric_cast.rs:39:13
+   |
+LL |     let _ = abc as isize;
+   |             ^^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u8`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:41:13
+   |
+LL |     let _ = abc as u8;
+   |             ^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u16`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:42:13
+   |
+LL |     let _ = abc as u16;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:43:13
+   |
+LL |     let _ = abc as u32;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u64`
+  --> $DIR/fn_to_numeric_cast.rs:44:13
+   |
+LL |     let _ = abc as u64;
+   |             ^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `abc` to `u128`
+  --> $DIR/fn_to_numeric_cast.rs:45:13
+   |
+LL |     let _ = abc as u128;
+   |             ^^^^^^^^^^^ help: try: `abc as usize`
+
+error: casting function pointer `f` to `i32`, which truncates the value
+  --> $DIR/fn_to_numeric_cast.rs:52:5
+   |
+LL |     f as i32
+   |     ^^^^^^^^ help: try: `f as usize`
+
+error: aborting due to 23 previous errors
+
diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs
new file mode 100644 (file)
index 0000000..39a8d96
--- /dev/null
@@ -0,0 +1,50 @@
+#![warn(clippy::for_kv_map)]
+#![allow(clippy::used_underscore_binding)]
+
+use std::collections::*;
+use std::rc::Rc;
+
+fn main() {
+    let m: HashMap<u64, u64> = HashMap::new();
+    for (_, v) in &m {
+        let _v = v;
+    }
+
+    let m: Rc<HashMap<u64, u64>> = Rc::new(HashMap::new());
+    for (_, v) in &*m {
+        let _v = v;
+        // Here the `*` is not actually necessary, but the test tests that we don't
+        // suggest
+        // `in *m.values()` as we used to
+    }
+
+    let mut m: HashMap<u64, u64> = HashMap::new();
+    for (_, v) in &mut m {
+        let _v = v;
+    }
+
+    let m: &mut HashMap<u64, u64> = &mut HashMap::new();
+    for (_, v) in &mut *m {
+        let _v = v;
+    }
+
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    for (k, _value) in rm {
+        let _k = k;
+    }
+
+    // The following should not produce warnings.
+
+    let m: HashMap<u64, u64> = HashMap::new();
+    // No error, _value is actually used
+    for (k, _value) in &m {
+        let _ = _value;
+        let _k = k;
+    }
+
+    let m: HashMap<u64, String> = Default::default();
+    for (_, v) in m {
+        let _v = v;
+    }
+}
diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr
new file mode 100644 (file)
index 0000000..ebe7585
--- /dev/null
@@ -0,0 +1,54 @@
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:9:19
+   |
+LL |     for (_, v) in &m {
+   |                   ^^
+   |
+   = note: `-D clippy::for-kv-map` implied by `-D warnings`
+help: use the corresponding method
+   |
+LL |     for v in m.values() {
+   |         ^    ^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:14:19
+   |
+LL |     for (_, v) in &*m {
+   |                   ^^^
+help: use the corresponding method
+   |
+LL |     for v in (*m).values() {
+   |         ^    ^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:22:19
+   |
+LL |     for (_, v) in &mut m {
+   |                   ^^^^^^
+help: use the corresponding method
+   |
+LL |     for v in m.values_mut() {
+   |         ^    ^^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:27:19
+   |
+LL |     for (_, v) in &mut *m {
+   |                   ^^^^^^^
+help: use the corresponding method
+   |
+LL |     for v in (*m).values_mut() {
+   |         ^    ^^^^^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's keys
+  --> $DIR/for_kv_map.rs:33:24
+   |
+LL |     for (k, _value) in rm {
+   |                        ^^
+help: use the corresponding method
+   |
+LL |     for k in rm.keys() {
+   |         ^    ^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
index bc0c3172bf0652e9d6177f7eb7061c5b38a82004..f13f826b1cc4e803538e54ebbd7dff60a370dde1 100644 (file)
@@ -1,67 +1,10 @@
-
-
-
 use std::collections::*;
 use std::rc::Rc;
 
 static STATIC: [usize; 4] = [0, 1, 8, 16];
 const CONST: [usize; 4] = [0, 1, 8, 16];
 
-#[warn(clippy)]
-fn for_loop_over_option_and_result() {
-    let option = Some(1);
-    let result = option.ok_or("x not found");
-    let v = vec![0, 1, 2];
-
-    // check FOR_LOOP_OVER_OPTION lint
-    for x in option {
-        println!("{}", x);
-    }
-
-    // check FOR_LOOP_OVER_RESULT lint
-    for x in result {
-        println!("{}", x);
-    }
-
-    for x in option.ok_or("x not found") {
-        println!("{}", x);
-    }
-
-    // make sure LOOP_OVER_NEXT lint takes precedence when next() is the last call
-    // in the chain
-    for x in v.iter().next() {
-        println!("{}", x);
-    }
-
-    // make sure we lint when next() is not the last call in the chain
-    for x in v.iter().next().and(Some(0)) {
-        println!("{}", x);
-    }
-
-    for x in v.iter().next().ok_or("x not found") {
-        println!("{}", x);
-    }
-
-    // check for false positives
-
-    // for loop false positive
-    for x in v {
-        println!("{}", x);
-    }
-
-    // while let false positive for Option
-    while let Some(x) = option {
-        println!("{}", x);
-        break;
-    }
-
-    // while let false positive for Result
-    while let Ok(x) = result {
-        println!("{}", x);
-        break;
-    }
-}
-
+#[warn(clippy::all)]
 struct Unrelated(Vec<u8>);
 impl Unrelated {
     fn next(&self) -> std::slice::Iter<u8> {
@@ -73,77 +16,26 @@ fn iter(&self) -> std::slice::Iter<u8> {
     }
 }
 
-#[warn(needless_range_loop, explicit_iter_loop, explicit_into_iter_loop, iter_next_loop, reverse_range_loop,
-       explicit_counter_loop, for_kv_map)]
-#[warn(unused_collect)]
-#[allow(linkedlist, shadow_unrelated, unnecessary_mut_passed, cyclomatic_complexity, similar_names)]
-#[allow(many_single_char_names, unused_variables)]
+#[warn(
+    clippy::needless_range_loop,
+    clippy::explicit_iter_loop,
+    clippy::explicit_into_iter_loop,
+    clippy::iter_next_loop,
+    clippy::reverse_range_loop,
+    clippy::for_kv_map
+)]
+#[warn(clippy::unused_collect)]
+#[allow(
+    clippy::linkedlist,
+    clippy::shadow_unrelated,
+    clippy::unnecessary_mut_passed,
+    clippy::cognitive_complexity,
+    clippy::similar_names
+)]
+#[allow(clippy::many_single_char_names, unused_variables, clippy::into_iter_on_array)]
 fn main() {
     const MAX_LEN: usize = 42;
-
     let mut vec = vec![1, 2, 3, 4];
-    let vec2 = vec![1, 2, 3, 4];
-    for i in 0..vec.len() {
-        println!("{}", vec[i]);
-    }
-
-    for i in 0..vec.len() {
-        let i = 42; // make a different `i`
-        println!("{}", vec[i]); // ok, not the `i` of the for-loop
-    }
-
-    for i in 0..vec.len() {
-        let _ = vec[i];
-    }
-
-    // ICE #746
-    for j in 0..4 {
-        println!("{:?}", STATIC[j]);
-    }
-
-    for j in 0..4 {
-        println!("{:?}", CONST[j]);
-    }
-
-    for i in 0..vec.len() {
-        println!("{} {}", vec[i], i);
-    }
-    for i in 0..vec.len() {
-        // not an error, indexing more than one variable
-        println!("{} {}", vec[i], vec2[i]);
-    }
-
-    for i in 0..vec.len() {
-        println!("{}", vec2[i]);
-    }
-
-    for i in 5..vec.len() {
-        println!("{}", vec[i]);
-    }
-
-    for i in 0..MAX_LEN {
-        println!("{}", vec[i]);
-    }
-
-    for i in 0..=MAX_LEN {
-        println!("{}", vec[i]);
-    }
-
-    for i in 5..10 {
-        println!("{}", vec[i]);
-    }
-
-    for i in 5..=10 {
-        println!("{}", vec[i]);
-    }
-
-    for i in 5..vec.len() {
-        println!("{} {}", vec[i], i);
-    }
-
-    for i in 5..10 {
-        println!("{} {}", vec[i], i);
-    }
 
     for i in 10..0 {
         println!("{}", i);
@@ -265,16 +157,6 @@ fn main() {
     let _y = vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>(); // this is fine
 
     // Loop with explicit counter variable
-    let mut _index = 0;
-    for _v in &vec {
-        _index += 1
-    }
-
-    let mut _index = 1;
-    _index = 0;
-    for _v in &vec {
-        _index += 1
-    }
 
     // Potential false positives
     let mut _index = 0;
@@ -379,39 +261,6 @@ fn main() {
     }
     println!("index: {}", index);
 
-    for_loop_over_option_and_result();
-
-    let m: HashMap<u64, u64> = HashMap::new();
-    for (_, v) in &m {
-        let _v = v;
-    }
-
-    let m: Rc<HashMap<u64, u64>> = Rc::new(HashMap::new());
-    for (_, v) in &*m {
-        let _v = v;
-        // Here the `*` is not actually necessary, but the test tests that we don't
-        // suggest
-        // `in *m.values()` as we used to
-    }
-
-    let mut m: HashMap<u64, u64> = HashMap::new();
-    for (_, v) in &mut m {
-        let _v = v;
-    }
-
-    let m: &mut HashMap<u64, u64> = &mut HashMap::new();
-    for (_, v) in &mut *m {
-        let _v = v;
-    }
-
-    let m: HashMap<u64, u64> = HashMap::new();
-    let rm = &m;
-    for (k, _value) in rm {
-        let _k = k;
-    }
-
-    test_for_kv_map();
-
     fn f<T>(_: &T, _: &T) -> bool {
         unimplemented!()
     }
@@ -429,17 +278,6 @@ fn g<T>(_: &mut [T], _: usize, _: usize) {
     }
 }
 
-#[allow(used_underscore_binding)]
-fn test_for_kv_map() {
-    let m: HashMap<u64, u64> = HashMap::new();
-
-    // No error, _value is actually used
-    for (k, _value) in &m {
-        let _ = _value;
-        let _k = k;
-    }
-}
-
 #[allow(dead_code)]
 fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
     let pivot = v.len() - 1;
@@ -454,102 +292,7 @@ fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
     i
 }
 
-const LOOP_OFFSET: usize = 5000;
-
-#[warn(needless_range_loop)]
-pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
-    // plain manual memcpy
-    for i in 0..src.len() {
-        dst[i] = src[i];
-    }
-
-    // dst offset memcpy
-    for i in 0..src.len() {
-        dst[i + 10] = src[i];
-    }
-
-    // src offset memcpy
-    for i in 0..src.len() {
-        dst[i] = src[i + 10];
-    }
-
-    // src offset memcpy
-    for i in 11..src.len() {
-        dst[i] = src[i - 10];
-    }
-
-    // overwrite entire dst
-    for i in 0..dst.len() {
-        dst[i] = src[i];
-    }
-
-    // manual copy with branch - can't easily convert to memcpy!
-    for i in 0..src.len() {
-        dst[i] = src[i];
-        if dst[i] > 5 {
-            break;
-        }
-    }
-
-    // multiple copies - suggest two memcpy statements
-    for i in 10..256 {
-        dst[i] = src[i - 5];
-        dst2[i + 500] = src[i]
-    }
-
-    // this is a reversal - the copy lint shouldn't be triggered
-    for i in 10..LOOP_OFFSET {
-        dst[i + LOOP_OFFSET] = src[LOOP_OFFSET - i];
-    }
-
-    let some_var = 5;
-    // Offset in variable
-    for i in 10..LOOP_OFFSET {
-        dst[i + LOOP_OFFSET] = src[i - some_var];
-    }
-
-    // Non continuous copy - don't trigger lint
-    for i in 0..10 {
-        dst[i + i] = src[i];
-    }
-
-    let src_vec = vec![1, 2, 3, 4, 5];
-    let mut dst_vec = vec![0, 0, 0, 0, 0];
-
-    // make sure vectors are supported
-    for i in 0..src_vec.len() {
-        dst_vec[i] = src_vec[i];
-    }
-
-    // lint should not trigger when either
-    // source or destination type is not
-    // slice-like, like DummyStruct
-    struct DummyStruct(i32);
-
-    impl ::std::ops::Index<usize> for DummyStruct {
-        type Output = i32;
-
-        fn index(&self, _: usize) -> &i32 {
-            &self.0
-        }
-    }
-
-    let src = DummyStruct(5);
-    let mut dst_vec = vec![0; 10];
-
-    for i in 0..10 {
-        dst_vec[i] = src[i];
-    }
-}
-
-#[warn(needless_range_loop)]
-pub fn manual_clone(src: &[String], dst: &mut [String]) {
-    for i in 0..src.len() {
-        dst[i] = src[i].clone();
-    }
-}
-
-#[warn(needless_range_loop)]
+#[warn(clippy::needless_range_loop)]
 pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) {
     // Same source and destination - don't trigger lint
     for i in 0..dst.len() {
index 582ca84b1339387e56f9d9328a1b75be08b0a4db..a18eb20774d596a3450cb71bb9df3aa90e34683f 100644 (file)
-error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement.
-  --> $DIR/for_loop.rs:17:14
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:40:14
    |
-17 |     for x in option {
-   |              ^^^^^^
+LL |     for i in 10..0 {
+   |              ^^^^^
+   |
+   = note: `-D clippy::reverse-range-loop` implied by `-D warnings`
+help: consider using the following if you are attempting to iterate over this range in reverse
    |
-   = note: `-D for-loop-over-option` implied by `-D warnings`
-   = help: consider replacing `for x in option` with `if let Some(x) = option`
+LL |     for i in (0..10).rev() {
+   |              ^^^^^^^^^^^^^
 
-error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement.
-  --> $DIR/for_loop.rs:22:14
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:44:14
    |
-22 |     for x in result {
+LL |     for i in 10..=0 {
    |              ^^^^^^
+help: consider using the following if you are attempting to iterate over this range in reverse
    |
-   = note: `-D for-loop-over-result` implied by `-D warnings`
-   = help: consider replacing `for x in result` with `if let Ok(x) = result`
+LL |     for i in (0...10).rev() {
+   |              ^^^^^^^^^^^^^^
 
-error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement.
-  --> $DIR/for_loop.rs:26:14
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:48:14
    |
-26 |     for x in option.ok_or("x not found") {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     for i in MAX_LEN..0 {
+   |              ^^^^^^^^^^
+help: consider using the following if you are attempting to iterate over this range in reverse
    |
-   = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")`
+LL |     for i in (0..MAX_LEN).rev() {
+   |              ^^^^^^^^^^^^^^^^^^
 
-error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
-  --> $DIR/for_loop.rs:32:14
-   |
-32 |     for x in v.iter().next() {
-   |              ^^^^^^^^^^^^^^^
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:52:14
    |
-   = note: `-D iter-next-loop` implied by `-D warnings`
+LL |     for i in 5..5 {
+   |              ^^^^
 
-error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement.
-  --> $DIR/for_loop.rs:37:14
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:77:14
    |
-37 |     for x in v.iter().next().and(Some(0)) {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     for i in 10..5 + 4 {
+   |              ^^^^^^^^^
+help: consider using the following if you are attempting to iterate over this range in reverse
    |
-   = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))`
+LL |     for i in (5 + 4..10).rev() {
+   |              ^^^^^^^^^^^^^^^^^
 
-error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement.
-  --> $DIR/for_loop.rs:41:14
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:81:14
    |
-41 |     for x in v.iter().next().ok_or("x not found") {
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     for i in (5 + 2)..(3 - 1) {
+   |              ^^^^^^^^^^^^^^^^
+help: consider using the following if you are attempting to iterate over this range in reverse
    |
-   = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
+LL |     for i in ((3 - 1)..(5 + 2)).rev() {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this loop never actually loops
-  --> $DIR/for_loop.rs:53:5
-   |
-53 | /     while let Some(x) = option {
-54 | |         println!("{}", x);
-55 | |         break;
-56 | |     }
-   | |_____^
+error: this range is empty so this for loop will never run
+  --> $DIR/for_loop.rs:85:14
    |
-   = note: `-D never-loop` implied by `-D warnings`
-
-error: this loop never actually loops
-  --> $DIR/for_loop.rs:59:5
-   |
-59 | /     while let Ok(x) = result {
-60 | |         println!("{}", x);
-61 | |         break;
-62 | |     }
-   | |_____^
+LL |     for i in (5 + 2)..(8 - 1) {
+   |              ^^^^^^^^^^^^^^^^
 
-error: the loop variable `i` is only used to index `vec`.
-  --> $DIR/for_loop.rs:86:14
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:107:15
    |
-86 |     for i in 0..vec.len() {
-   |              ^^^^^^^^^^^^
+LL |     for _v in vec.iter() {}
+   |               ^^^^^^^^^^
    |
-   = note: `-D needless-range-loop` implied by `-D warnings`
-help: consider using an iterator
+   = note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
+
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:109:15
    |
-86 |     for <item> in &vec {
-   |         ^^^^^^    ^^^^
+LL |     for _v in vec.iter_mut() {}
+   |               ^^^^^^^^^^^^^^
 
-error: the loop variable `i` is only used to index `vec`.
-  --> $DIR/for_loop.rs:95:14
+error: it is more concise to loop over containers instead of using explicit iteration methods`
+  --> $DIR/for_loop.rs:112:15
    |
-95 |     for i in 0..vec.len() {
-   |              ^^^^^^^^^^^^
-help: consider using an iterator
+LL |     for _v in out_vec.into_iter() {}
+   |               ^^^^^^^^^^^^^^^^^^^
    |
-95 |     for <item> in &vec {
-   |         ^^^^^^    ^^^^
-
-error: the loop variable `j` is only used to index `STATIC`.
-   --> $DIR/for_loop.rs:100:14
-    |
-100 |     for j in 0..4 {
-    |              ^^^^
-help: consider using an iterator
-    |
-100 |     for <item> in STATIC.iter().take(4) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `j` is only used to index `CONST`.
-   --> $DIR/for_loop.rs:104:14
-    |
-104 |     for j in 0..4 {
-    |              ^^^^
-help: consider using an iterator
-    |
-104 |     for <item> in CONST.iter().take(4) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is used to index `vec`
-   --> $DIR/for_loop.rs:108:14
-    |
-108 |     for i in 0..vec.len() {
-    |              ^^^^^^^^^^^^
-help: consider using an iterator
-    |
-108 |     for (i, <item>) in vec.iter().enumerate() {
-    |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is only used to index `vec2`.
-   --> $DIR/for_loop.rs:116:14
-    |
-116 |     for i in 0..vec.len() {
-    |              ^^^^^^^^^^^^
-help: consider using an iterator
-    |
-116 |     for <item> in vec2.iter().take(vec.len()) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is only used to index `vec`.
-   --> $DIR/for_loop.rs:120:14
-    |
-120 |     for i in 5..vec.len() {
-    |              ^^^^^^^^^^^^
-help: consider using an iterator
-    |
-120 |     for <item> in vec.iter().skip(5) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is only used to index `vec`.
-   --> $DIR/for_loop.rs:124:14
-    |
-124 |     for i in 0..MAX_LEN {
-    |              ^^^^^^^^^^
-help: consider using an iterator
-    |
-124 |     for <item> in vec.iter().take(MAX_LEN) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is only used to index `vec`.
-   --> $DIR/for_loop.rs:128:14
-    |
-128 |     for i in 0..=MAX_LEN {
-    |              ^^^^^^^^^^^
-help: consider using an iterator
-    |
-128 |     for <item> in vec.iter().take(MAX_LEN + 1) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is only used to index `vec`.
-   --> $DIR/for_loop.rs:132:14
-    |
-132 |     for i in 5..10 {
-    |              ^^^^^
-help: consider using an iterator
-    |
-132 |     for <item> in vec.iter().take(10).skip(5) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is only used to index `vec`.
-   --> $DIR/for_loop.rs:136:14
-    |
-136 |     for i in 5..=10 {
-    |              ^^^^^^
-help: consider using an iterator
-    |
-136 |     for <item> in vec.iter().take(10 + 1).skip(5) {
-    |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is used to index `vec`
-   --> $DIR/for_loop.rs:140:14
-    |
-140 |     for i in 5..vec.len() {
-    |              ^^^^^^^^^^^^
-help: consider using an iterator
-    |
-140 |     for (i, <item>) in vec.iter().enumerate().skip(5) {
-    |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the loop variable `i` is used to index `vec`
-   --> $DIR/for_loop.rs:144:14
-    |
-144 |     for i in 5..10 {
-    |              ^^^^^
-help: consider using an iterator
-    |
-144 |     for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
-    |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:148:14
-    |
-148 |     for i in 10..0 {
-    |              ^^^^^
-    |
-    = note: `-D reverse-range-loop` implied by `-D warnings`
-help: consider using the following if you are attempting to iterate over this range in reverse
-    |
-148 |     for i in (0..10).rev() {
-    |              ^^^^^^^^^^^^^
-
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:152:14
-    |
-152 |     for i in 10..=0 {
-    |              ^^^^^^
-help: consider using the following if you are attempting to iterate over this range in reverse
-    |
-152 |     for i in (0...10).rev() {
-    |              ^^^^^^^^^^^^^^
-
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:156:14
-    |
-156 |     for i in MAX_LEN..0 {
-    |              ^^^^^^^^^^
-help: consider using the following if you are attempting to iterate over this range in reverse
-    |
-156 |     for i in (0..MAX_LEN).rev() {
-    |              ^^^^^^^^^^^^^^^^^^
-
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:160:14
-    |
-160 |     for i in 5..5 {
-    |              ^^^^
+   = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings`
 
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:185:14
-    |
-185 |     for i in 10..5 + 4 {
-    |              ^^^^^^^^^
-help: consider using the following if you are attempting to iterate over this range in reverse
-    |
-185 |     for i in (5 + 4..10).rev() {
-    |              ^^^^^^^^^^^^^^^^^
-
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:189:14
-    |
-189 |     for i in (5 + 2)..(3 - 1) {
-    |              ^^^^^^^^^^^^^^^^
-help: consider using the following if you are attempting to iterate over this range in reverse
-    |
-189 |     for i in ((3 - 1)..(5 + 2)).rev() {
-    |              ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: this range is empty so this for loop will never run
-   --> $DIR/for_loop.rs:193:14
-    |
-193 |     for i in (5 + 2)..(8 - 1) {
-    |              ^^^^^^^^^^^^^^^^
-
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:215:15
-    |
-215 |     for _v in vec.iter() {}
-    |               ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
-    |
-    = note: `-D explicit-iter-loop` implied by `-D warnings`
-
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:217:15
-    |
-217 |     for _v in vec.iter_mut() {}
-    |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
-
-error: it is more idiomatic to loop over containers instead of using explicit iteration methods`
-   --> $DIR/for_loop.rs:220:15
-    |
-220 |     for _v in out_vec.into_iter() {}
-    |               ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec`
-    |
-    = note: `-D explicit-into-iter-loop` implied by `-D warnings`
-
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:223:15
-    |
-223 |     for _v in array.into_iter() {}
-    |               ^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&array`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:115:15
+   |
+LL |     for _v in array.into_iter() {}
+   |               ^^^^^^^^^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:228:15
-    |
-228 |     for _v in [1, 2, 3].iter() {}
-    |               ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:120:15
+   |
+LL |     for _v in [1, 2, 3].iter() {}
+   |               ^^^^^^^^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:232:15
-    |
-232 |     for _v in [0; 32].iter() {}
-    |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:124:15
+   |
+LL |     for _v in [0; 32].iter() {}
+   |               ^^^^^^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:237:15
-    |
-237 |     for _v in ll.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&ll`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:129:15
+   |
+LL |     for _v in ll.iter() {}
+   |               ^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:240:15
-    |
-240 |     for _v in vd.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&vd`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:132:15
+   |
+LL |     for _v in vd.iter() {}
+   |               ^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:243:15
-    |
-243 |     for _v in bh.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&bh`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:135:15
+   |
+LL |     for _v in bh.iter() {}
+   |               ^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:246:15
-    |
-246 |     for _v in hm.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&hm`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:138:15
+   |
+LL |     for _v in hm.iter() {}
+   |               ^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:249:15
-    |
-249 |     for _v in bt.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&bt`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:141:15
+   |
+LL |     for _v in bt.iter() {}
+   |               ^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:252:15
-    |
-252 |     for _v in hs.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&hs`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:144:15
+   |
+LL |     for _v in hs.iter() {}
+   |               ^^^^^^^^^
 
-error: it is more idiomatic to loop over references to containers instead of using explicit iteration methods
-   --> $DIR/for_loop.rs:255:15
-    |
-255 |     for _v in bs.iter() {}
-    |               ^^^^^^^^^ help: to write this more concisely, try: `&bs`
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> $DIR/for_loop.rs:147:15
+   |
+LL |     for _v in bs.iter() {}
+   |               ^^^^^^^^^
 
 error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
-   --> $DIR/for_loop.rs:257:15
-    |
-257 |     for _v in vec.iter().next() {}
-    |               ^^^^^^^^^^^^^^^^^
+  --> $DIR/for_loop.rs:149:15
+   |
+LL |     for _v in vec.iter().next() {}
+   |               ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-next-loop` implied by `-D warnings`
 
 error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator
-   --> $DIR/for_loop.rs:264:5
-    |
-264 |     vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: `-D unused-collect` implied by `-D warnings`
-
-error: the variable `_index` is used as a loop counter. Consider using `for (_index, item) in &vec.enumerate()` or similar iterators
-   --> $DIR/for_loop.rs:269:15
-    |
-269 |     for _v in &vec {
-    |               ^^^^
-    |
-    = note: `-D explicit-counter-loop` implied by `-D warnings`
-
-error: the variable `_index` is used as a loop counter. Consider using `for (_index, item) in &vec.enumerate()` or similar iterators
-   --> $DIR/for_loop.rs:275:15
-    |
-275 |     for _v in &vec {
-    |               ^^^^
-
-error: you seem to want to iterate on a map's values
-   --> $DIR/for_loop.rs:385:19
-    |
-385 |     for (_, v) in &m {
-    |                   ^^
-    |
-    = note: `-D for-kv-map` implied by `-D warnings`
-help: use the corresponding method
-    |
-385 |     for v in m.values() {
-    |         ^    ^^^^^^^^^^
-
-error: you seem to want to iterate on a map's values
-   --> $DIR/for_loop.rs:390:19
-    |
-390 |     for (_, v) in &*m {
-    |                   ^^^
-help: use the corresponding method
-    |
-390 |     for v in (*m).values() {
-    |         ^    ^^^^^^^^^^^^^
-
-error: you seem to want to iterate on a map's values
-   --> $DIR/for_loop.rs:398:19
-    |
-398 |     for (_, v) in &mut m {
-    |                   ^^^^^^
-help: use the corresponding method
-    |
-398 |     for v in m.values_mut() {
-    |         ^    ^^^^^^^^^^^^^^
-
-error: you seem to want to iterate on a map's values
-   --> $DIR/for_loop.rs:403:19
-    |
-403 |     for (_, v) in &mut *m {
-    |                   ^^^^^^^
-help: use the corresponding method
-    |
-403 |     for v in (*m).values_mut() {
-    |         ^    ^^^^^^^^^^^^^^^^^
-
-error: you seem to want to iterate on a map's keys
-   --> $DIR/for_loop.rs:409:24
-    |
-409 |     for (k, _value) in rm {
-    |                        ^^
-help: use the corresponding method
-    |
-409 |     for k in rm.keys() {
-    |         ^    ^^^^^^^^^
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:462:14
-    |
-462 |     for i in 0..src.len() {
-    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
-    |
-    = note: `-D manual-memcpy` implied by `-D warnings`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:467:14
-    |
-467 |     for i in 0..src.len() {
-    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:472:14
-    |
-472 |     for i in 0..src.len() {
-    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:477:14
-    |
-477 |     for i in 11..src.len() {
-    |              ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:482:14
-    |
-482 |     for i in 0..dst.len() {
-    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:495:14
-    |
-495 |     for i in 10..256 {
-    |              ^^^^^^^
-help: try replacing the loop by
-    |
-495 |     for i in dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)])
-496 |     dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) {
-    |
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:507:14
-    |
-507 |     for i in 10..LOOP_OFFSET {
-    |              ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:520:14
-    |
-520 |     for i in 0..src_vec.len() {
-    |              ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])`
-
-error: it looks like you're manually copying between slices
-   --> $DIR/for_loop.rs:547:14
-    |
-547 |     for i in 0..src.len() {
-    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
+  --> $DIR/for_loop.rs:156:5
+   |
+LL |     vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unused-collect` implied by `-D warnings`
 
-error: aborting due to 59 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/tests/ui/for_loop.stdout b/tests/ui/for_loop.stdout
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/ui/for_loop_over_option_result.rs b/tests/ui/for_loop_over_option_result.rs
new file mode 100644 (file)
index 0000000..6b207b2
--- /dev/null
@@ -0,0 +1,59 @@
+#![warn(clippy::for_loop_over_option, clippy::for_loop_over_result)]
+
+/// Tests for_loop_over_result and for_loop_over_option
+
+fn for_loop_over_option_and_result() {
+    let option = Some(1);
+    let result = option.ok_or("x not found");
+    let v = vec![0, 1, 2];
+
+    // check FOR_LOOP_OVER_OPTION lint
+    for x in option {
+        println!("{}", x);
+    }
+
+    // check FOR_LOOP_OVER_RESULT lint
+    for x in result {
+        println!("{}", x);
+    }
+
+    for x in option.ok_or("x not found") {
+        println!("{}", x);
+    }
+
+    // make sure LOOP_OVER_NEXT lint takes clippy::precedence when next() is the last call
+    // in the chain
+    for x in v.iter().next() {
+        println!("{}", x);
+    }
+
+    // make sure we lint when next() is not the last call in the chain
+    for x in v.iter().next().and(Some(0)) {
+        println!("{}", x);
+    }
+
+    for x in v.iter().next().ok_or("x not found") {
+        println!("{}", x);
+    }
+
+    // check for false positives
+
+    // for loop false positive
+    for x in v {
+        println!("{}", x);
+    }
+
+    // while let false positive for Option
+    while let Some(x) = option {
+        println!("{}", x);
+        break;
+    }
+
+    // while let false positive for Result
+    while let Ok(x) = result {
+        println!("{}", x);
+        break;
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/for_loop_over_option_result.stderr b/tests/ui/for_loop_over_option_result.stderr
new file mode 100644 (file)
index 0000000..5414bfc
--- /dev/null
@@ -0,0 +1,72 @@
+error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:11:14
+   |
+LL |     for x in option {
+   |              ^^^^^^
+   |
+   = note: `-D clippy::for-loop-over-option` implied by `-D warnings`
+   = help: consider replacing `for x in option` with `if let Some(x) = option`
+
+error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:16:14
+   |
+LL |     for x in result {
+   |              ^^^^^^
+   |
+   = note: `-D clippy::for-loop-over-result` implied by `-D warnings`
+   = help: consider replacing `for x in result` with `if let Ok(x) = result`
+
+error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:20:14
+   |
+LL |     for x in option.ok_or("x not found") {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")`
+
+error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
+  --> $DIR/for_loop_over_option_result.rs:26:14
+   |
+LL |     for x in v.iter().next() {
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: #[deny(clippy::iter_next_loop)] on by default
+
+error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:31:14
+   |
+LL |     for x in v.iter().next().and(Some(0)) {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))`
+
+error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement.
+  --> $DIR/for_loop_over_option_result.rs:35:14
+   |
+LL |     for x in v.iter().next().ok_or("x not found") {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
+
+error: this loop never actually loops
+  --> $DIR/for_loop_over_option_result.rs:47:5
+   |
+LL | /     while let Some(x) = option {
+LL | |         println!("{}", x);
+LL | |         break;
+LL | |     }
+   | |_____^
+   |
+   = note: #[deny(clippy::never_loop)] on by default
+
+error: this loop never actually loops
+  --> $DIR/for_loop_over_option_result.rs:53:5
+   |
+LL | /     while let Ok(x) = result {
+LL | |         println!("{}", x);
+LL | |         break;
+LL | |     }
+   | |_____^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed
new file mode 100644 (file)
index 0000000..e421741
--- /dev/null
@@ -0,0 +1,62 @@
+// run-rustfix
+
+#![allow(clippy::print_literal)]
+#![warn(clippy::useless_format)]
+
+struct Foo(pub String);
+
+macro_rules! foo {
+    ($($t:tt)*) => (Foo(format!($($t)*)))
+}
+
+fn main() {
+    "foo".to_string();
+    "{}".to_string();
+    "{} abc {}".to_string();
+
+    "foo".to_string();
+    format!("{:?}", "foo"); // Don't warn about `Debug`.
+    format!("{:8}", "foo");
+    format!("{:width$}", "foo", width = 8);
+    "foo".to_string(); // Warn when the format makes no difference.
+    "foo".to_string(); // Warn when the format makes no difference.
+    format!("foo {}", "bar");
+    format!("{} bar", "foo");
+
+    let arg: String = "".to_owned();
+    arg.to_string();
+    format!("{:?}", arg); // Don't warn about debug.
+    format!("{:8}", arg);
+    format!("{:width$}", arg, width = 8);
+    arg.to_string(); // Warn when the format makes no difference.
+    arg.to_string(); // Warn when the format makes no difference.
+    format!("foo {}", arg);
+    format!("{} bar", arg);
+
+    // We don’t want to warn for non-string args; see issue #697.
+    format!("{}", 42);
+    format!("{:?}", 42);
+    format!("{:+}", 42);
+    format!("foo {}", 42);
+    format!("{} bar", 42);
+
+    // We only want to warn about `format!` itself.
+    println!("foo");
+    println!("{}", "foo");
+    println!("foo {}", "foo");
+    println!("{}", 42);
+    println!("foo {}", 42);
+
+    // A `format!` inside a macro should not trigger a warning.
+    foo!("should not warn");
+
+    // Precision on string means slicing without panicking on size.
+    format!("{:.1}", "foo"); // Could be `"foo"[..1]`
+    format!("{:.10}", "foo"); // Could not be `"foo"[..10]`
+    format!("{:.prec$}", "foo", prec = 1);
+    format!("{:.prec$}", "foo", prec = 10);
+
+    42.to_string();
+    let x = std::path::PathBuf::from("/bar/foo/qux");
+    x.display().to_string();
+}
index 783c6ea095dc2b09eb4be3a67083f4139fef98e0..61ef3e7243d794eda5987b92e2c9c55c7232c626 100644 (file)
@@ -1,47 +1,62 @@
+// run-rustfix
 
-#![allow(print_literal)]
-#![warn(useless_format)]
+#![allow(clippy::print_literal)]
+#![warn(clippy::useless_format)]
 
 struct Foo(pub String);
 
 macro_rules! foo {
-  ($($t:tt)*) => (Foo(format!($($t)*)))
+    ($($t:tt)*) => (Foo(format!($($t)*)))
 }
 
 fn main() {
     format!("foo");
+    format!("{{}}");
+    format!("{{}} abc {{}}");
 
     format!("{}", "foo");
-    format!("{:?}", "foo"); // don't warn about debug
+    format!("{:?}", "foo"); // Don't warn about `Debug`.
     format!("{:8}", "foo");
-    format!("{:+}", "foo"); // warn when the format makes no difference
-    format!("{:<}", "foo"); // warn when the format makes no difference
+    format!("{:width$}", "foo", width = 8);
+    format!("{:+}", "foo"); // Warn when the format makes no difference.
+    format!("{:<}", "foo"); // Warn when the format makes no difference.
     format!("foo {}", "bar");
     format!("{} bar", "foo");
 
     let arg: String = "".to_owned();
     format!("{}", arg);
-    format!("{:?}", arg); // don't warn about debug
+    format!("{:?}", arg); // Don't warn about debug.
     format!("{:8}", arg);
-    format!("{:+}", arg); // warn when the format makes no difference
-    format!("{:<}", arg); // warn when the format makes no difference
+    format!("{:width$}", arg, width = 8);
+    format!("{:+}", arg); // Warn when the format makes no difference.
+    format!("{:<}", arg); // Warn when the format makes no difference.
     format!("foo {}", arg);
     format!("{} bar", arg);
 
-    // we don’t want to warn for non-string args, see #697
+    // We don’t want to warn for non-string args; see issue #697.
     format!("{}", 42);
     format!("{:?}", 42);
     format!("{:+}", 42);
     format!("foo {}", 42);
     format!("{} bar", 42);
 
-    // we only want to warn about `format!` itself
+    // We only want to warn about `format!` itself.
     println!("foo");
     println!("{}", "foo");
     println!("foo {}", "foo");
     println!("{}", 42);
     println!("foo {}", 42);
 
-    // A format! inside a macro should not trigger a warning
+    // A `format!` inside a macro should not trigger a warning.
     foo!("should not warn");
+
+    // Precision on string means slicing without panicking on size.
+    format!("{:.1}", "foo"); // Could be `"foo"[..1]`
+    format!("{:.10}", "foo"); // Could not be `"foo"[..10]`
+    format!("{:.prec$}", "foo", prec = 1);
+    format!("{:.prec$}", "foo", prec = 10);
+
+    format!("{}", 42.to_string());
+    let x = std::path::PathBuf::from("/bar/foo/qux");
+    format!("{}", x.display().to_string());
 }
index fa5c740c551b51f953ead07dc34bfa1d2854043a..ec1253589f625e43a8ee94fdbf522ea51203b33e 100644 (file)
@@ -1,58 +1,70 @@
 error: useless use of `format!`
-  --> $DIR/format.rs:12:5
+  --> $DIR/format.rs:13:5
    |
-12 |     format!("foo");
-   |     ^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()`
+LL |     format!("foo");
+   |     ^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string();`
    |
-   = note: `-D useless-format` implied by `-D warnings`
+   = note: `-D clippy::useless-format` implied by `-D warnings`
 
 error: useless use of `format!`
   --> $DIR/format.rs:14:5
    |
-14 |     format!("{}", "foo");
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()`
+LL |     format!("{{}}");
+   |     ^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"{}".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:15:5
    |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     format!("{{}} abc {{}}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"{} abc {}".to_string();`
 
 error: useless use of `format!`
   --> $DIR/format.rs:17:5
    |
-17 |     format!("{:+}", "foo"); // warn when the format makes no difference
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()`
-   |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     format!("{}", "foo");
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string();`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:18:5
+  --> $DIR/format.rs:21:5
    |
-18 |     format!("{:<}", "foo"); // warn when the format makes no difference
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string()`
-   |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string();`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:23:5
+  --> $DIR/format.rs:22:5
    |
-23 |     format!("{}", arg);
-   |     ^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()`
+LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `"foo".to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:27:5
    |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     format!("{}", arg);
+   |     ^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string();`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:26:5
+  --> $DIR/format.rs:31:5
    |
-26 |     format!("{:+}", arg); // warn when the format makes no difference
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()`
+LL |     format!("{:+}", arg); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:32:5
    |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     format!("{:<}", arg); // Warn when the format makes no difference.
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string();`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:27:5
+  --> $DIR/format.rs:59:5
    |
-27 |     format!("{:<}", arg); // warn when the format makes no difference
-   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using .to_string(): `arg.to_string()`
+LL |     format!("{}", 42.to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `42.to_string();`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:61:5
    |
-   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+LL |     format!("{}", x.display().to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `to_string()` is enough: `x.display().to_string();`
 
-error: aborting due to 7 previous errors
+error: aborting due to 11 previous errors
 
index 20b1c1655a7284a858a1320c212c8e912b1634e8..149f1da93966c5d6d9524e41029c0b04e2eba4d7 100644 (file)
@@ -1,16 +1,20 @@
-
-
-
-#![warn(clippy)]
+#![warn(clippy::all)]
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
-#![allow(if_same_then_else)]
-#![allow(deref_addrof)]
+#![allow(clippy::if_same_then_else)]
+#![allow(clippy::deref_addrof)]
 
-fn foo() -> bool { true }
+fn foo() -> bool {
+    true
+}
 
+#[rustfmt::skip]
 fn main() {
-    // weird `else if` formatting:
+    // weird `else` formatting:
+    if foo() {
+    } {
+    }
+
     if foo() {
     } if foo() {
     }
@@ -35,6 +39,17 @@ fn main() {
         let _ = 0;
     };
 
+    if foo() {
+    } else
+    {
+    }
+
+    if foo() {
+    }
+    else
+    {
+    }
+
     if foo() {
     } else
     if foo() { // the span of the above error should continue here
@@ -47,6 +62,20 @@ fn main() {
     }
 
     // those are ok:
+    if foo() {
+    }
+    {
+    }
+
+    if foo() {
+    } else {
+    }
+
+    if foo() {
+    }
+    else {
+    }
+
     if foo() {
     }
     if foo() {
@@ -102,4 +131,16 @@ fn main() {
         1 + 2, 3 +
         4, 5 + 6,
     ];
+
+    // don't lint for bin op without unary equiv
+    // issue 3244
+    vec![
+        1
+        / 2,
+    ];
+    // issue 3396
+    vec![
+        true
+        | false,
+    ];
 }
index 266de262ea0aa94bcae4ae45e88b2484eda999dd..29a5c55bc34b7512a1528294a6c5d830e7f9eedf 100644 (file)
-error: this looks like an `else if` but the `else` is missing
+error: this looks like an `else {..}` but the `else` is missing
   --> $DIR/formatting.rs:15:6
    |
-15 |     } if foo() {
+LL |     } {
+   |      ^
+   |
+   = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings`
+   = note: to remove this lint, add the missing `else` or add a new line before the next block
+
+error: this looks like an `else if` but the `else` is missing
+  --> $DIR/formatting.rs:19:6
+   |
+LL |     } if foo() {
    |      ^
    |
-   = note: `-D suspicious-else-formatting` implied by `-D warnings`
    = note: to remove this lint, add the missing `else` or add a new line before the second `if`
 
 error: this looks like an `else if` but the `else` is missing
-  --> $DIR/formatting.rs:22:10
+  --> $DIR/formatting.rs:26:10
    |
-22 |         } if foo() {
+LL |         } if foo() {
    |          ^
    |
    = note: to remove this lint, add the missing `else` or add a new line before the second `if`
 
 error: this looks like an `else if` but the `else` is missing
-  --> $DIR/formatting.rs:30:10
+  --> $DIR/formatting.rs:34:10
    |
-30 |         } if foo() {
+LL |         } if foo() {
    |          ^
    |
    = note: to remove this lint, add the missing `else` or add a new line before the second `if`
 
+error: this is an `else {..}` but the formatting might hide it
+  --> $DIR/formatting.rs:43:6
+   |
+LL |       } else
+   |  ______^
+LL | |     {
+   | |____^
+   |
+   = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
+error: this is an `else {..}` but the formatting might hide it
+  --> $DIR/formatting.rs:48:6
+   |
+LL |       }
+   |  ______^
+LL | |     else
+LL | |     {
+   | |____^
+   |
+   = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
+
 error: this is an `else if` but the formatting might hide it
-  --> $DIR/formatting.rs:39:6
+  --> $DIR/formatting.rs:54:6
    |
-39 |       } else
+LL |       } else
    |  ______^
-40 | |     if foo() { // the span of the above error should continue here
+LL | |     if foo() { // the span of the above error should continue here
    | |____^
    |
    = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
 
 error: this is an `else if` but the formatting might hide it
-  --> $DIR/formatting.rs:44:6
+  --> $DIR/formatting.rs:59:6
    |
-44 |       }
+LL |       }
    |  ______^
-45 | |     else
-46 | |     if foo() { // the span of the above error should continue here
+LL | |     else
+LL | |     if foo() { // the span of the above error should continue here
    | |____^
    |
    = note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
 
 error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
-  --> $DIR/formatting.rs:71:6
+  --> $DIR/formatting.rs:100:6
    |
-71 |     a =- 35;
+LL |     a =- 35;
    |      ^^^^
    |
-   = note: `-D suspicious-assignment-formatting` implied by `-D warnings`
+   = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings`
    = note: to remove this lint, use either `-=` or `= -`
 
 error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
-  --> $DIR/formatting.rs:72:6
+  --> $DIR/formatting.rs:101:6
    |
-72 |     a =* &191;
+LL |     a =* &191;
    |      ^^^^
    |
    = note: to remove this lint, use either `*=` or `= *`
 
 error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
-  --> $DIR/formatting.rs:75:6
+  --> $DIR/formatting.rs:104:6
    |
-75 |     b =! false;
+LL |     b =! false;
    |      ^^^^
    |
    = note: to remove this lint, use either `!=` or `= !`
 
 error: possibly missing a comma here
-  --> $DIR/formatting.rs:84:19
+  --> $DIR/formatting.rs:113:19
    |
-84 |         -1, -2, -3 // <= no comma here
+LL |         -1, -2, -3 // <= no comma here
    |                   ^
    |
-   = note: `-D possible-missing-comma` implied by `-D warnings`
+   = note: `-D clippy::possible-missing-comma` implied by `-D warnings`
    = note: to remove this lint, add a comma or write the expr in a single line
 
 error: possibly missing a comma here
-  --> $DIR/formatting.rs:88:19
+  --> $DIR/formatting.rs:117:19
    |
-88 |         -1, -2, -3 // <= no comma here
+LL |         -1, -2, -3 // <= no comma here
    |                   ^
    |
    = note: to remove this lint, add a comma or write the expr in a single line
 
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
 
index 5688c471d86b1630343a62d72062f79768f1c67f..f8de18dc6243ea2a0c1e7a300214405ecb39c172 100644 (file)
@@ -1,18 +1,44 @@
-
-
-
-#![warn(clippy)]
+#![warn(clippy::all)]
 #![allow(dead_code)]
 #![allow(unused_unsafe)]
 
 // TOO_MANY_ARGUMENTS
 fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {}
 
-fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {
+fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+
+#[rustfmt::skip]
+fn bad_multiline(
+    one: u32,
+    two: u32,
+    three: &str,
+    four: bool,
+    five: f32,
+    six: f32,
+    seven: bool,
+    eight: ()
+) {
+    let _one = one;
+    let _two = two;
+    let _three = three;
+    let _four = four;
+    let _five = five;
+    let _six = six;
+    let _seven = seven;
 }
 
 // don't lint extern fns
-extern fn extern_fn(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+extern "C" fn extern_fn(
+    _one: u32,
+    _two: u32,
+    _three: &str,
+    _four: bool,
+    _five: f32,
+    _six: f32,
+    _seven: bool,
+    _eight: (),
+) {
+}
 
 pub trait Foo {
     fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool);
index 0a97748954f348f10b35342505f34f846b6e0382..10d72fb96b1d497702b4725429a5c880003f3bd6 100644 (file)
@@ -1,79 +1,90 @@
+error: this function has too many arguments (8/7)
+  --> $DIR/functions.rs:8:1
+   |
+LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::too-many-arguments` implied by `-D warnings`
+
 error: this function has too many arguments (8/7)
   --> $DIR/functions.rs:11:1
    |
-11 | / fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {
-12 | | }
+LL | / fn bad_multiline(
+LL | |     one: u32,
+LL | |     two: u32,
+LL | |     three: &str,
+...  |
+LL | |     eight: ()
+LL | | ) {
    | |_^
-   |
-   = note: `-D too-many-arguments` implied by `-D warnings`
 
 error: this function has too many arguments (8/7)
-  --> $DIR/functions.rs:19:5
+  --> $DIR/functions.rs:45:5
    |
-19 |     fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
+LL |     fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this function has too many arguments (8/7)
-  --> $DIR/functions.rs:28:5
+  --> $DIR/functions.rs:54:5
    |
-28 |     fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:37:34
+  --> $DIR/functions.rs:63:34
    |
-37 |         println!("{}", unsafe { *p });
+LL |         println!("{}", unsafe { *p });
    |                                  ^
    |
-   = note: `-D not-unsafe-ptr-arg-deref` implied by `-D warnings`
+   = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:38:35
+  --> $DIR/functions.rs:64:35
    |
-38 |         println!("{:?}", unsafe { p.as_ref() });
+LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:39:33
+  --> $DIR/functions.rs:65:33
    |
-39 |         unsafe { std::ptr::read(p) };
+LL |         unsafe { std::ptr::read(p) };
    |                                 ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:50:30
+  --> $DIR/functions.rs:76:30
    |
-50 |     println!("{}", unsafe { *p });
+LL |     println!("{}", unsafe { *p });
    |                              ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:51:31
+  --> $DIR/functions.rs:77:31
    |
-51 |     println!("{:?}", unsafe { p.as_ref() });
+LL |     println!("{:?}", unsafe { p.as_ref() });
    |                               ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:52:29
+  --> $DIR/functions.rs:78:29
    |
-52 |     unsafe { std::ptr::read(p) };
+LL |     unsafe { std::ptr::read(p) };
    |                             ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:61:34
+  --> $DIR/functions.rs:87:34
    |
-61 |         println!("{}", unsafe { *p });
+LL |         println!("{}", unsafe { *p });
    |                                  ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:62:35
+  --> $DIR/functions.rs:88:35
    |
-62 |         println!("{:?}", unsafe { p.as_ref() });
+LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
 error: this public function dereferences a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:63:33
+  --> $DIR/functions.rs:89:33
    |
-63 |         unsafe { std::ptr::read(p) };
+LL |         unsafe { std::ptr::read(p) };
    |                                 ^
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/functions_maxlines.rs b/tests/ui/functions_maxlines.rs
new file mode 100644 (file)
index 0000000..ada35ab
--- /dev/null
@@ -0,0 +1,162 @@
+#![warn(clippy::too_many_lines)]
+
+fn good_lines() {
+    /* println!("This is good."); */
+    // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* */ // println!("This is good.");
+    /* println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good."); */
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+    println!("This is good.");
+}
+
+fn bad_lines() {
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+    println!("This is bad.");
+}
+
+fn main() {}
diff --git a/tests/ui/functions_maxlines.stderr b/tests/ui/functions_maxlines.stderr
new file mode 100644 (file)
index 0000000..dfa6a1c
--- /dev/null
@@ -0,0 +1,16 @@
+error: This function has a large number of lines.
+  --> $DIR/functions_maxlines.rs:58:1
+   |
+LL | / fn bad_lines() {
+LL | |     println!("This is bad.");
+LL | |     println!("This is bad.");
+LL | |     println!("This is bad.");
+...  |
+LL | |     println!("This is bad.");
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::too-many-lines` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed
new file mode 100644 (file)
index 0000000..97e6b20
--- /dev/null
@@ -0,0 +1,62 @@
+// run-rustfix
+#![allow(unused_mut)]
+#![deny(clippy::get_unwrap)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+use std::iter::FromIterator;
+
+struct GetFalsePositive {
+    arr: [u32; 3],
+}
+
+impl GetFalsePositive {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
+        self.arr.get_mut(pos)
+    }
+}
+
+fn main() {
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_slice = &mut [0, 1, 2, 3];
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
+    let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
+    let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
+
+    {
+        // Test `get().unwrap()`
+        let _ = &boxed_slice[1];
+        let _ = &some_slice[0];
+        let _ = &some_vec[0];
+        let _ = &some_vecdeque[0];
+        let _ = &some_hashmap[&1];
+        let _ = &some_btreemap[&1];
+        let _ = false_positive.get(0).unwrap();
+        // Test with deref
+        let _: u8 = boxed_slice[1];
+    }
+
+    {
+        // Test `get_mut().unwrap()`
+        boxed_slice[0] = 1;
+        some_slice[0] = 1;
+        some_vec[0] = 1;
+        some_vecdeque[0] = 1;
+        // Check false positives
+        *some_hashmap.get_mut(&1).unwrap() = 'b';
+        *some_btreemap.get_mut(&1).unwrap() = 'b';
+        *false_positive.get_mut(0).unwrap() = 1;
+    }
+
+    {
+        // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
+        let _ = some_vec[0..1].to_vec();
+        let _ = some_vec[0..1].to_vec();
+    }
+}
index a10d4d18262050861274bd289e39bd5d8a41d46f..1c9a71c09699afda778d8dba35896571a672d997 100644 (file)
@@ -1,4 +1,6 @@
+// run-rustfix
 #![allow(unused_mut)]
+#![deny(clippy::get_unwrap)]
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
@@ -10,8 +12,12 @@ struct GetFalsePositive {
 }
 
 impl GetFalsePositive {
-    fn get(&self, pos: usize) -> Option<&u32> { self.arr.get(pos) }
-    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> { self.arr.get_mut(pos) }
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+    fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
+        self.arr.get_mut(pos)
+    }
 }
 
 fn main() {
@@ -23,7 +29,8 @@ fn main() {
     let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
     let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
 
-    { // Test `get().unwrap()`
+    {
+        // Test `get().unwrap()`
         let _ = boxed_slice.get(1).unwrap();
         let _ = some_slice.get(0).unwrap();
         let _ = some_vec.get(0).unwrap();
@@ -31,9 +38,12 @@ fn main() {
         let _ = some_hashmap.get(&1).unwrap();
         let _ = some_btreemap.get(&1).unwrap();
         let _ = false_positive.get(0).unwrap();
+        // Test with deref
+        let _: u8 = *boxed_slice.get(1).unwrap();
     }
 
-    { // Test `get_mut().unwrap()`
+    {
+        // Test `get_mut().unwrap()`
         *boxed_slice.get_mut(0).unwrap() = 1;
         *some_slice.get_mut(0).unwrap() = 1;
         *some_vec.get_mut(0).unwrap() = 1;
@@ -43,4 +53,10 @@ fn main() {
         *some_btreemap.get_mut(&1).unwrap() = 'b';
         *false_positive.get_mut(0).unwrap() = 1;
     }
+
+    {
+        // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
+        let _ = some_vec.get(0..1).unwrap().to_vec();
+        let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+    }
 }
index b5ada86253199fdca77a44534cf4bc3f5fe243d3..b27bef6d1cc9d65bb80d462feb82398c533ec037 100644 (file)
@@ -1,64 +1,86 @@
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:27:17
+  --> $DIR/get_unwrap.rs:34:17
    |
-27 |         let _ = boxed_slice.get(1).unwrap();
+LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
    |
-   = note: `-D get-unwrap` implied by `-D warnings`
+note: lint level defined here
+  --> $DIR/get_unwrap.rs:3:9
+   |
+LL | #![deny(clippy::get_unwrap)]
+   |         ^^^^^^^^^^^^^^^^^^
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:28:17
+  --> $DIR/get_unwrap.rs:35:17
    |
-28 |         let _ = some_slice.get(0).unwrap();
+LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:29:17
+  --> $DIR/get_unwrap.rs:36:17
    |
-29 |         let _ = some_vec.get(0).unwrap();
+LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
 
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:30:17
+  --> $DIR/get_unwrap.rs:37:17
    |
-30 |         let _ = some_vecdeque.get(0).unwrap();
+LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
 
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:31:17
+  --> $DIR/get_unwrap.rs:38:17
    |
-31 |         let _ = some_hashmap.get(&1).unwrap();
+LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
 
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:32:17
+  --> $DIR/get_unwrap.rs:39:17
    |
-32 |         let _ = some_btreemap.get(&1).unwrap();
+LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
 
+error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:42:21
+   |
+LL |         let _: u8 = *boxed_slice.get(1).unwrap();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
+
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:37:10
+  --> $DIR/get_unwrap.rs:47:9
    |
-37 |         *boxed_slice.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut boxed_slice[0]`
+LL |         *boxed_slice.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:38:10
+  --> $DIR/get_unwrap.rs:48:9
    |
-38 |         *some_slice.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_slice[0]`
+LL |         *some_slice.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:39:10
+  --> $DIR/get_unwrap.rs:49:9
    |
-39 |         *some_vec.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vec[0]`
+LL |         *some_vec.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
 
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:40:10
+  --> $DIR/get_unwrap.rs:50:9
+   |
+LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
+
+error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:59:17
+   |
+LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
+
+error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
+  --> $DIR/get_unwrap.rs:60:17
    |
-40 |         *some_vecdeque.get_mut(0).unwrap() = 1;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut some_vecdeque[0]`
+LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
 
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/ice-2636.rs b/tests/ui/ice-2636.rs
new file mode 100644 (file)
index 0000000..e0b5815
--- /dev/null
@@ -0,0 +1,22 @@
+#![allow(dead_code)]
+
+enum Foo {
+    A,
+    B,
+    C,
+}
+
+macro_rules! test_hash {
+    ($foo:expr, $($t:ident => $ord:expr),+ ) => {
+        use self::Foo::*;
+        match $foo {
+            $ ( & $t => $ord,
+            )*
+        };
+    };
+}
+
+fn main() {
+    let a = Foo::A;
+    test_hash!(&a, A => 0, B => 1, C => 2);
+}
diff --git a/tests/ui/ice-2636.stderr b/tests/ui/ice-2636.stderr
new file mode 100644 (file)
index 0000000..aba8be4
--- /dev/null
@@ -0,0 +1,16 @@
+error: you don't need to add `&` to both the expression and the patterns
+  --> $DIR/ice-2636.rs:12:9
+   |
+LL | /         match $foo {
+LL | |             $ ( & $t => $ord,
+LL | |             )*
+LL | |         };
+   | |_________^
+...
+LL |       test_hash!(&a, A => 0, B => 1, C => 2);
+   |       --------------------------------------- in this macro invocation
+   |
+   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/ice-360.rs b/tests/ui/ice-360.rs
new file mode 100644 (file)
index 0000000..6555c19
--- /dev/null
@@ -0,0 +1,12 @@
+fn main() {}
+
+fn no_panic<T>(slice: &[T]) {
+    let mut iter = slice.iter();
+    loop {
+        let _ = match iter.next() {
+            Some(ele) => ele,
+            None => break,
+        };
+        loop {}
+    }
+}
diff --git a/tests/ui/ice-360.stderr b/tests/ui/ice-360.stderr
new file mode 100644 (file)
index 0000000..84e31ea
--- /dev/null
@@ -0,0 +1,24 @@
+error: this loop could be written as a `while let` loop
+  --> $DIR/ice-360.rs:5:5
+   |
+LL | /     loop {
+LL | |         let _ = match iter.next() {
+LL | |             Some(ele) => ele,
+LL | |             None => break,
+LL | |         };
+LL | |         loop {}
+LL | |     }
+   | |_____^ help: try: `while let Some(ele) = iter.next() { .. }`
+   |
+   = note: `-D clippy::while-let-loop` implied by `-D warnings`
+
+error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+  --> $DIR/ice-360.rs:10:9
+   |
+LL |         loop {}
+   |         ^^^^^^^
+   |
+   = note: `-D clippy::empty-loop` implied by `-D warnings`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/ice-3717.rs b/tests/ui/ice-3717.rs
new file mode 100644 (file)
index 0000000..21c48f4
--- /dev/null
@@ -0,0 +1,8 @@
+use std::collections::HashSet;
+
+fn main() {}
+
+pub fn ice_3717(_: &HashSet<usize>) {
+    let _ = [0u8; 0];
+    let _: HashSet<usize> = HashSet::new();
+}
diff --git a/tests/ui/ice-3717.stderr b/tests/ui/ice-3717.stderr
new file mode 100644 (file)
index 0000000..08c53c3
--- /dev/null
@@ -0,0 +1,18 @@
+error: parameter of type `HashSet` should be generalized over different hashers
+  --> $DIR/ice-3717.rs:5:21
+   |
+LL | pub fn ice_3717(_: &HashSet<usize>) {
+   |                     ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::implicit-hasher` implied by `-D warnings`
+help: consider adding a type parameter
+   |
+LL | pub fn ice_3717<S: ::std::hash::BuildHasher + Default>(_: &HashSet<usize, S>) {
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^
+help: ...and use generic constructor
+   |
+LL |     let _: HashSet<usize> = HashSet::default();
+   |                             ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index d254b746d79fe4e79a1cd2a76890f581e7cad6d1..164f0a3d6e73ab388bdbd787d640aaf30d32441a 100644 (file)
@@ -1,4 +1,4 @@
-#![deny(identity_conversion)]
+#![deny(clippy::identity_conversion)]
 
 fn test_generic<T: Copy>(val: T) -> T {
     let _ = T::from(val);
@@ -20,21 +20,37 @@ fn test_questionmark() -> Result<(), ()> {
     Ok(())
 }
 
+fn test_issue_3913() -> Result<(), std::io::Error> {
+    use std::fs;
+    use std::path::Path;
+
+    let path = Path::new(".");
+    for _ in fs::read_dir(path)? {}
+
+    Ok(())
+}
+
 fn main() {
     test_generic(10i32);
     test_generic2::<i32, i32>(10i32);
     test_questionmark().unwrap();
+    test_issue_3913().unwrap();
 
     let _: String = "foo".into();
     let _: String = From::from("foo");
     let _ = String::from("foo");
-    #[allow(identity_conversion)]
+    #[allow(clippy::identity_conversion)]
     {
         let _: String = "foo".into();
         let _ = String::from("foo");
+        let _ = "".lines().into_iter();
     }
 
     let _: String = "foo".to_string().into();
     let _: String = From::from("foo".to_string());
     let _ = String::from("foo".to_string());
+    let _ = String::from(format!("A: {:04}", 123));
+    let _ = "".lines().into_iter();
+    let _ = vec![1, 2, 3].into_iter().into_iter();
+    let _: String = format!("Hello {}", "world").into();
 }
index 1ae3f229dd88c7fb08b5279217ce9e1ab08a3ddd..663f00d22795c29966b19566731715d29b78b8af 100644 (file)
@@ -1,44 +1,68 @@
 error: identical conversion
- --> $DIR/identity_conversion.rs:4:13
-  |
-4 |     let _ = T::from(val);
-  |             ^^^^^^^^^^^^ help: consider removing `T::from()`: `val`
-  |
 --> $DIR/identity_conversion.rs:4:13
+   |
+LL |     let _ = T::from(val);
+   |             ^^^^^^^^^^^^ help: consider removing `T::from()`: `val`
+   |
 note: lint level defined here
- --> $DIR/identity_conversion.rs:1:9
-  |
-1 | #![deny(identity_conversion)]
-  |         ^^^^^^^^^^^^^^^^^^^
 --> $DIR/identity_conversion.rs:1:9
+   |
+LL | #![deny(clippy::identity_conversion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: identical conversion
- --> $DIR/identity_conversion.rs:5:5
-  |
-5 |     val.into()
-  |     ^^^^^^^^^^ help: consider removing `.into()`: `val`
 --> $DIR/identity_conversion.rs:5:5
+   |
+LL |     val.into()
+   |     ^^^^^^^^^^ help: consider removing `.into()`: `val`
 
 error: identical conversion
   --> $DIR/identity_conversion.rs:17:22
    |
-17 |         let _: i32 = 0i32.into();
+LL |         let _: i32 = 0i32.into();
    |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 
 error: identical conversion
-  --> $DIR/identity_conversion.rs:37:21
+  --> $DIR/identity_conversion.rs:49:21
    |
-37 |     let _: String = "foo".to_string().into();
+LL |     let _: String = "foo".to_string().into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 
 error: identical conversion
-  --> $DIR/identity_conversion.rs:38:21
+  --> $DIR/identity_conversion.rs:50:21
    |
-38 |     let _: String = From::from("foo".to_string());
+LL |     let _: String = From::from("foo".to_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 
 error: identical conversion
-  --> $DIR/identity_conversion.rs:39:13
+  --> $DIR/identity_conversion.rs:51:13
    |
-39 |     let _ = String::from("foo".to_string());
+LL |     let _ = String::from("foo".to_string());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 
-error: aborting due to 6 previous errors
+error: identical conversion
+  --> $DIR/identity_conversion.rs:52:13
+   |
+LL |     let _ = String::from(format!("A: {:04}", 123));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:53:13
+   |
+LL |     let _ = "".lines().into_iter();
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:54:13
+   |
+LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
+
+error: identical conversion
+  --> $DIR/identity_conversion.rs:55:21
+   |
+LL |     let _: String = format!("Hello {}", "world").into();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
+
+error: aborting due to 10 previous errors
 
index 1ed9f974d436c2b4c0f3e863755b137e41a80229..ae2815d345a94dd5233f3177ceb707bd5e47497a 100644 (file)
@@ -1,12 +1,15 @@
-
-
-
-const ONE : i64 = 1;
-const NEG_ONE : i64 = -1;
-const ZERO : i64 = 0;
-
-#[allow(eq_op, no_effect, unnecessary_operation, double_parens)]
-#[warn(identity_op)]
+const ONE: i64 = 1;
+const NEG_ONE: i64 = -1;
+const ZERO: i64 = 0;
+
+#[allow(
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::double_parens
+)]
+#[warn(clippy::identity_op)]
+#[rustfmt::skip]
 fn main() {
     let x = 0;
 
@@ -15,19 +18,19 @@ fn main() {
     x + 1;
     0 + x;
     1 + x;
-    x - ZERO;     //no error, as we skip lookups (for now)
+    x - ZERO; //no error, as we skip lookups (for now)
     x | (0);
     ((ZERO)) | x; //no error, as we skip lookups (for now)
 
     x * 1;
     1 * x;
-    x / ONE;      //no error, as we skip lookups (for now)
+    x / ONE; //no error, as we skip lookups (for now)
 
-    x / 2;        //no false positive
+    x / 2; //no false positive
 
-    x & NEG_ONE;  //no error, as we skip lookups (for now)
+    x & NEG_ONE; //no error, as we skip lookups (for now)
     -1 & x;
 
-    let u : u8 = 0;
+    let u: u8 = 0;
     u & 255;
 }
index 45f579ce832f97f4eeb80f73987ce2c220084b1c..4742877706acd6d360768c41dfbe4f0b8011d8c7 100644 (file)
@@ -1,51 +1,51 @@
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:13:5
+  --> $DIR/identity_op.rs:16:5
    |
-13 |     x + 0;
+LL |     x + 0;
    |     ^^^^^
    |
-   = note: `-D identity-op` implied by `-D warnings`
+   = note: `-D clippy::identity-op` implied by `-D warnings`
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:14:5
+  --> $DIR/identity_op.rs:17:5
    |
-14 |     x + (1 - 1);
+LL |     x + (1 - 1);
    |     ^^^^^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:16:5
+  --> $DIR/identity_op.rs:19:5
    |
-16 |     0 + x;
+LL |     0 + x;
    |     ^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:19:5
+  --> $DIR/identity_op.rs:22:5
    |
-19 |     x | (0);
+LL |     x | (0);
    |     ^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:22:5
+  --> $DIR/identity_op.rs:25:5
    |
-22 |     x * 1;
+LL |     x * 1;
    |     ^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:23:5
+  --> $DIR/identity_op.rs:26:5
    |
-23 |     1 * x;
+LL |     1 * x;
    |     ^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:29:5
+  --> $DIR/identity_op.rs:32:5
    |
-29 |     -1 & x;
+LL |     -1 & x;
    |     ^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `u`
-  --> $DIR/identity_op.rs:32:5
+  --> $DIR/identity_op.rs:35:5
    |
-32 |     u & 255;
+LL |     u & 255;
    |     ^^^^^^^
 
 error: aborting due to 8 previous errors
diff --git a/tests/ui/if_let_redundant_pattern_matching.rs b/tests/ui/if_let_redundant_pattern_matching.rs
deleted file mode 100644 (file)
index 0963caa..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-#![warn(clippy)]
-#![warn(if_let_redundant_pattern_matching)]
-
-
-fn main() {
-    if let Ok(_) = Ok::<i32, i32>(42) {}
-
-    if let Err(_) = Err::<i32, i32>(42) {
-    }
-
-    if let None = None::<()> {
-    }
-
-    if let Some(_) = Some(42) {
-    }
-
-    if Ok::<i32, i32>(42).is_ok() {
-    }
-
-    if Err::<i32, i32>(42).is_err() {
-    }
-
-    if None::<i32>.is_none() {
-    }
-
-    if Some(42).is_some() {
-    }
-
-    if let Ok(x) = Ok::<i32,i32>(42) {
-        println!("{}", x);
-    }
-}
diff --git a/tests/ui/if_let_redundant_pattern_matching.stderr b/tests/ui/if_let_redundant_pattern_matching.stderr
deleted file mode 100644 (file)
index e7bfd02..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/if_let_redundant_pattern_matching.rs:9:12
-  |
-9 |     if let Ok(_) = Ok::<i32, i32>(42) {}
-  |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
-  |
-  = note: `-D if-let-redundant-pattern-matching` implied by `-D warnings`
-
-error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/if_let_redundant_pattern_matching.rs:11:12
-   |
-11 |     if let Err(_) = Err::<i32, i32>(42) {
-   |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/if_let_redundant_pattern_matching.rs:14:12
-   |
-14 |     if let None = None::<()> {
-   |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/if_let_redundant_pattern_matching.rs:17:12
-   |
-17 |     if let Some(_) = Some(42) {
-   |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
-
-error: aborting due to 4 previous errors
-
index 9436af70cb8f6524ce1c7a2e13f3f5dc31158a57..dc3fb1ceac9a44ba1dd69d063040b49f9feff534 100644 (file)
@@ -1,9 +1,9 @@
+#![warn(clippy::all)]
+#![warn(clippy::if_not_else)]
 
-
-#![warn(clippy)]
-#![warn(if_not_else)]
-
-fn bla() -> bool { unimplemented!() }
+fn bla() -> bool {
+    unimplemented!()
+}
 
 fn main() {
     if !bla() {
index b920ef3b625065e1a6af856927da59d0579af81e..3694f5aec53648eada6a650374672200fb13d21d 100644 (file)
@@ -1,24 +1,24 @@
 error: Unnecessary boolean `not` operation
   --> $DIR/if_not_else.rs:9:5
    |
- | /     if !bla() {
-10 | |         println!("Bugs");
-11 | |     } else {
-12 | |         println!("Bunny");
-13 | |     }
+LL | /     if !bla() {
+LL | |         println!("Bugs");
+LL | |     } else {
+LL | |         println!("Bunny");
+LL | |     }
    | |_____^
    |
-   = note: `-D if-not-else` implied by `-D warnings`
+   = note: `-D clippy::if-not-else` implied by `-D warnings`
    = help: remove the `!` and swap the blocks of the if/else
 
 error: Unnecessary `!=` operation
   --> $DIR/if_not_else.rs:14:5
    |
-14 | /     if 4 != 5 {
-15 | |         println!("Bugs");
-16 | |     } else {
-17 | |         println!("Bunny");
-18 | |     }
+LL | /     if 4 != 5 {
+LL | |         println!("Bugs");
+LL | |     } else {
+LL | |         println!("Bunny");
+LL | |     }
    | |_____^
    |
    = help: change to `==` and swap the blocks of the if/else
diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs
new file mode 100644 (file)
index 0000000..0ec933e
--- /dev/null
@@ -0,0 +1,262 @@
+#![warn(clippy::if_same_then_else)]
+#![allow(
+    clippy::blacklisted_name,
+    clippy::collapsible_if,
+    clippy::cognitive_complexity,
+    clippy::eq_op,
+    clippy::needless_return,
+    clippy::never_loop,
+    clippy::no_effect,
+    clippy::zero_divided_by_zero,
+    clippy::unused_unit
+)]
+
+struct Foo {
+    bar: u8,
+}
+
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn if_same_then_else() -> Result<&'static str, ()> {
+    if true {
+        Foo { bar: 42 };
+        0..10;
+        ..;
+        0..;
+        ..10;
+        0..=10;
+        foo();
+    } else {
+        //~ ERROR same body as `if` block
+        Foo { bar: 42 };
+        0..10;
+        ..;
+        0..;
+        ..10;
+        0..=10;
+        foo();
+    }
+
+    if true {
+        Foo { bar: 42 };
+    } else {
+        Foo { bar: 43 };
+    }
+
+    if true {
+        ();
+    } else {
+        ()
+    }
+
+    if true {
+        0..10;
+    } else {
+        0..=10;
+    }
+
+    if true {
+        foo();
+        foo();
+    } else {
+        foo();
+    }
+
+    let _ = if true {
+        0.0
+    } else {
+        //~ ERROR same body as `if` block
+        0.0
+    };
+
+    let _ = if true {
+        -0.0
+    } else {
+        //~ ERROR same body as `if` block
+        -0.0
+    };
+
+    let _ = if true { 0.0 } else { -0.0 };
+
+    // Different NaNs
+    let _ = if true { 0.0 / 0.0 } else { std::f32::NAN };
+
+    if true {
+        foo();
+    }
+
+    let _ = if true {
+        42
+    } else {
+        //~ ERROR same body as `if` block
+        42
+    };
+
+    if true {
+        for _ in &[42] {
+            let foo: &Option<_> = &Some::<u8>(42);
+            if true {
+                break;
+            } else {
+                continue;
+            }
+        }
+    } else {
+        //~ ERROR same body as `if` block
+        for _ in &[42] {
+            let foo: &Option<_> = &Some::<u8>(42);
+            if true {
+                break;
+            } else {
+                continue;
+            }
+        }
+    }
+
+    if true {
+        let bar = if true { 42 } else { 43 };
+
+        while foo() {
+            break;
+        }
+        bar + 1;
+    } else {
+        //~ ERROR same body as `if` block
+        let bar = if true { 42 } else { 43 };
+
+        while foo() {
+            break;
+        }
+        bar + 1;
+    }
+
+    if true {
+        let _ = match 42 {
+            42 => 1,
+            a if a > 0 => 2,
+            10..=15 => 3,
+            _ => 4,
+        };
+    } else if false {
+        foo();
+    } else if foo() {
+        let _ = match 42 {
+            42 => 1,
+            a if a > 0 => 2,
+            10..=15 => 3,
+            _ => 4,
+        };
+    }
+
+    if true {
+        if let Some(a) = Some(42) {}
+    } else {
+        //~ ERROR same body as `if` block
+        if let Some(a) = Some(42) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        //~ ERROR same body as `if` block
+        if let (1, .., 3) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        if let (.., 3) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        if let (.., 4) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let (1, .., 3) = (1, 2, 3) {}
+    } else {
+        if let (.., 1, 3) = (1, 2, 3) {}
+    }
+
+    if true {
+        if let Some(42) = None {}
+    } else {
+        if let Option::Some(42) = None {}
+    }
+
+    if true {
+        if let Some(42) = None::<u8> {}
+    } else {
+        if let Some(42) = None {}
+    }
+
+    if true {
+        if let Some(42) = None::<u8> {}
+    } else {
+        if let Some(42) = None::<u32> {}
+    }
+
+    if true {
+        if let Some(a) = Some(42) {}
+    } else {
+        if let Some(a) = Some(43) {}
+    }
+
+    // Same NaNs
+    let _ = if true {
+        std::f32::NAN
+    } else {
+        //~ ERROR same body as `if` block
+        std::f32::NAN
+    };
+
+    if true {
+        try!(Ok("foo"));
+    } else {
+        //~ ERROR same body as `if` block
+        try!(Ok("foo"));
+    }
+
+    if true {
+        let foo = "";
+        return Ok(&foo[0..]);
+    } else if false {
+        let foo = "bar";
+        return Ok(&foo[0..]);
+    } else {
+        let foo = "";
+        return Ok(&foo[0..]);
+    }
+
+    // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559.
+    if true {
+        let foo = "";
+        let (x, y) = (1, 2);
+        return Ok(&foo[x..y]);
+    } else {
+        let foo = "";
+        let (y, x) = (1, 2);
+        return Ok(&foo[x..y]);
+    }
+}
+
+// Issue #2423. This was causing an ICE.
+fn func() {
+    if true {
+        f(&[0; 62]);
+        f(&[0; 4]);
+        f(&[0; 3]);
+    } else {
+        f(&[0; 62]);
+        f(&[0; 6]);
+        f(&[0; 6]);
+    }
+}
+
+fn f(val: &[u8]) {}
+
+fn main() {}
diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr
new file mode 100644 (file)
index 0000000..b170db3
--- /dev/null
@@ -0,0 +1,214 @@
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:31:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         Foo { bar: 42 };
+LL | |         0..10;
+...  |
+LL | |         foo();
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::if-same-then-else` implied by `-D warnings`
+note: same as this
+  --> $DIR/if_same_then_else.rs:23:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         Foo { bar: 42 };
+LL | |         0..10;
+LL | |         ..;
+...  |
+LL | |         foo();
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:69:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         0.0
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:67:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         0.0
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:76:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         -0.0
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:74:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         -0.0
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:92:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         42
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:90:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         42
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:106:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         for _ in &[42] {
+LL | |             let foo: &Option<_> = &Some::<u8>(42);
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:97:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         for _ in &[42] {
+LL | |             let foo: &Option<_> = &Some::<u8>(42);
+LL | |             if true {
+...  |
+LL | |         }
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:125:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         let bar = if true { 42 } else { 43 };
+LL | |
+...  |
+LL | |         bar + 1;
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:118:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         let bar = if true { 42 } else { 43 };
+LL | |
+LL | |         while foo() {
+...  |
+LL | |         bar + 1;
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:155:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         if let Some(a) = Some(42) {}
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:153:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         if let Some(a) = Some(42) {}
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:162:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         if let (1, .., 3) = (1, 2, 3) {}
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:160:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         if let (1, .., 3) = (1, 2, 3) {}
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:212:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         std::f32::NAN
+LL | |     };
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:210:21
+   |
+LL |       let _ = if true {
+   |  _____________________^
+LL | |         std::f32::NAN
+LL | |     } else {
+   | |_____^
+
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:219:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         //~ ERROR same body as `if` block
+LL | |         try!(Ok("foo"));
+LL | |     }
+   | |_____^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:217:13
+   |
+LL |       if true {
+   |  _____________^
+LL | |         try!(Ok("foo"));
+LL | |     } else {
+   | |_____^
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs
new file mode 100644 (file)
index 0000000..b67e730
--- /dev/null
@@ -0,0 +1,46 @@
+#![warn(clippy::ifs_same_cond)]
+#![allow(clippy::if_same_then_else)] // all empty blocks
+
+fn ifs_same_cond() {
+    let a = 0;
+    let b = false;
+
+    if b {
+    } else if b {
+        //~ ERROR ifs same condition
+    }
+
+    if a == 1 {
+    } else if a == 1 {
+        //~ ERROR ifs same condition
+    }
+
+    if 2 * a == 1 {
+    } else if 2 * a == 2 {
+    } else if 2 * a == 1 {
+        //~ ERROR ifs same condition
+    } else if a == 1 {
+    }
+
+    // See #659
+    if cfg!(feature = "feature1-659") {
+        1
+    } else if cfg!(feature = "feature2-659") {
+        2
+    } else {
+        3
+    };
+
+    let mut v = vec![1];
+    if v.pop() == None {
+        // ok, functions
+    } else if v.pop() == None {
+    }
+
+    if v.len() == 42 {
+        // ok, functions
+    } else if v.len() == 42 {
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr
new file mode 100644 (file)
index 0000000..0b0dd24
--- /dev/null
@@ -0,0 +1,39 @@
+error: this `if` has the same condition as a previous if
+  --> $DIR/ifs_same_cond.rs:9:15
+   |
+LL |     } else if b {
+   |               ^
+   |
+   = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
+note: same as this
+  --> $DIR/ifs_same_cond.rs:8:8
+   |
+LL |     if b {
+   |        ^
+
+error: this `if` has the same condition as a previous if
+  --> $DIR/ifs_same_cond.rs:14:15
+   |
+LL |     } else if a == 1 {
+   |               ^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:13:8
+   |
+LL |     if a == 1 {
+   |        ^^^^^^
+
+error: this `if` has the same condition as a previous if
+  --> $DIR/ifs_same_cond.rs:20:15
+   |
+LL |     } else if 2 * a == 1 {
+   |               ^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:18:8
+   |
+LL |     if 2 * a == 1 {
+   |        ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index 9e10dbade4e3d415d57021e821f4106da93a4b37..1c46e3a5337828d3ca4a619cce8081d107f986ef 100644 (file)
@@ -1,5 +1,5 @@
 #![allow(dead_code)]
-#![warn(multiple_inherent_impl)]
+#![warn(clippy::multiple_inherent_impl)]
 
 struct MyStruct;
 
index 95e627cd50905042e0cb1858f7ed119ede93a4a3..585d32845d290af4f8e66a3b1fd9a41b13332f5a 100644 (file)
@@ -1,34 +1,34 @@
 error: Multiple implementations of this structure
   --> $DIR/impl.rs:10:1
    |
-10 | / impl MyStruct {
-11 | |     fn second() {}
-12 | | }
+LL | / impl MyStruct {
+LL | |     fn second() {}
+LL | | }
    | |_^
    |
-   = note: `-D multiple-inherent-impl` implied by `-D warnings`
+   = note: `-D clippy::multiple-inherent-impl` implied by `-D warnings`
 note: First implementation here
   --> $DIR/impl.rs:6:1
    |
- | / impl MyStruct {
- | |     fn first() {}
- | | }
+LL | / impl MyStruct {
+LL | |     fn first() {}
+LL | | }
    | |_^
 
 error: Multiple implementations of this structure
   --> $DIR/impl.rs:24:5
    |
-24 | /     impl super::MyStruct {
-25 | |         fn third() {}
-26 | |     }
+LL | /     impl super::MyStruct {
+LL | |         fn third() {}
+LL | |     }
    | |_____^
    |
 note: First implementation here
   --> $DIR/impl.rs:6:1
    |
- | / impl MyStruct {
- | |     fn first() {}
- | | }
+LL | / impl MyStruct {
+LL | |     fn first() {}
+LL | | }
    | |_^
 
 error: aborting due to 2 previous errors
index 49df39ca71bcbec5917ebfc39c9b378ee94355c2..064760e73f31967364ec707eef425316f42f1d1a 100644 (file)
@@ -1,8 +1,8 @@
 #![allow(unused)]
 
-use std::collections::{HashMap, HashSet};
 use std::cmp::Eq;
-use std::hash::{Hash, BuildHasher};
+use std::collections::{HashMap, HashSet};
+use std::hash::{BuildHasher, Hash};
 
 pub trait Foo<T>: Sized {
     fn make() -> (Self, Self);
@@ -39,7 +39,6 @@ fn make() -> (Self, Self) {
     }
 }
 
-
 impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
     fn make() -> (Self, Self) {
         (HashSet::new(), HashSet::with_capacity(10))
@@ -62,8 +61,7 @@ fn make() -> (Self, Self) {
     }
 }
 
-pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
-}
+pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
 
 macro_rules! gen {
     (impl) => {
@@ -75,11 +73,10 @@ fn make() -> (Self, Self) {
     };
 
     (fn $name:ident) => {
-        pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
-        }
-    }
+        pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
+    };
 }
-
+#[rustfmt::skip]
 gen!(impl);
 gen!(fn bar);
 
@@ -87,7 +84,8 @@ pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
 // and should not cause an ICE
 // See #2707
 #[macro_use]
-#[path = "../auxiliary/test_macro.rs"] pub mod test_macro;
+#[path = "../auxiliary/test_macro.rs"]
+pub mod test_macro;
 __implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
 
 fn main() {}
index f41ce40519f21638040f5da634521e20b6510991..68e305f0cb4ba117a8875ed492fcc45fece48019 100644 (file)
 error: impl for `HashMap` should be generalized over different hashers
   --> $DIR/implicit_hasher.rs:11:35
    |
-11 | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
+LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
    |                                   ^^^^^^^^^^^^^
    |
-   = note: `-D implicit-hasher` implied by `-D warnings`
+   = note: `-D clippy::implicit-hasher` implied by `-D warnings`
 help: consider adding a type parameter
    |
-11 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
+LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashMap<K, V, S> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             ^^^^^^^^^^^^^^^^
 help: ...and use generic constructor
    |
-17 |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
    |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: impl for `HashMap` should be generalized over different hashers
   --> $DIR/implicit_hasher.rs:20:36
    |
-20 | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
+LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
    |                                    ^^^^^^^^^^^^^
 help: consider adding a type parameter
    |
-20 | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
+LL | impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<i8> for (HashMap<K, V, S>,) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^
 help: ...and use generic constructor
    |
-22 |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
+LL |         ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),))
    |           ^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: impl for `HashMap` should be generalized over different hashers
   --> $DIR/implicit_hasher.rs:25:19
    |
-25 | impl Foo<i16> for HashMap<String, String> {
+LL | impl Foo<i16> for HashMap<String, String> {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^
 help: consider adding a type parameter
    |
-25 | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
+LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashMap<String, String, S> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: ...and use generic constructor
    |
-27 |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+LL |         (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
    |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: impl for `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:43:32
+  --> $DIR/implicit_hasher.rs:42:32
    |
-43 | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
+LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
    |                                ^^^^^^^^^^
 help: consider adding a type parameter
    |
-43 | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
+LL | impl<T: Hash + Eq, S: ::std::hash::BuildHasher + Default> Foo<i8> for HashSet<T, S> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             ^^^^^^^^^^^^^
 help: ...and use generic constructor
    |
-45 |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
    |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: impl for `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:48:19
+  --> $DIR/implicit_hasher.rs:47:19
    |
-48 | impl Foo<i16> for HashSet<String> {
+LL | impl Foo<i16> for HashSet<String> {
    |                   ^^^^^^^^^^^^^^^
 help: consider adding a type parameter
    |
-48 | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
+LL | impl<S: ::std::hash::BuildHasher + Default> Foo<i16> for HashSet<String, S> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^^^
 help: ...and use generic constructor
    |
-50 |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
+LL |         (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default()))
    |          ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:65:23
+  --> $DIR/implicit_hasher.rs:64:23
    |
-65 | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
+LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                       ^^^^^^^^^^^^^^^^^
 help: consider adding a type parameter
    |
-65 | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {
+LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^            ^^^^^^^^^^^^^^^^^^^^
 
 error: parameter of type `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:65:53
+  --> $DIR/implicit_hasher.rs:64:53
    |
-65 | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
+LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                                     ^^^^^^^^^^^^
 help: consider adding a type parameter
    |
-65 | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {
+LL | pub fn foo<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                          ^^^^^^^^^^^^^^^
 
 error: impl for `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:70:43
+  --> $DIR/implicit_hasher.rs:68:43
    |
-70 |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
+LL |         impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
    |                                           ^^^^^^^^^^^^^
 ...
-83 | gen!(impl);
+LL | gen!(impl);
    | ----------- in this macro invocation
 help: consider adding a type parameter
    |
-70 |         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
+LL |         impl<K: Hash + Eq, V, S: ::std::hash::BuildHasher + Default> Foo<u8> for HashMap<K, V, S> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^             ^^^^^^^^^^^^^^^^
 help: ...and use generic constructor
    |
-72 |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
+LL |                 (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default()))
    |                  ^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: parameter of type `HashMap` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:78:33
+  --> $DIR/implicit_hasher.rs:76:33
    |
-78 |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
+LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                 ^^^^^^^^^^^^^^^^^
 ...
-84 | gen!(fn bar);
+LL | gen!(fn bar);
    | ------------- in this macro invocation
 help: consider adding a type parameter
    |
-78 |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {
+LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32, S>, _set: &mut HashSet<i32>) {}
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^            ^^^^^^^^^^^^^^^^^^^^
 
 error: parameter of type `HashSet` should be generalized over different hashers
-  --> $DIR/implicit_hasher.rs:78:63
+  --> $DIR/implicit_hasher.rs:76:63
    |
-78 |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {
+LL |         pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
    |                                                               ^^^^^^^^^^^^
 ...
-84 | gen!(fn bar);
+LL | gen!(fn bar);
    | ------------- in this macro invocation
 help: consider adding a type parameter
    |
-78 |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {
+LL |         pub fn $name<S: ::std::hash::BuildHasher>(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32, S>) {}
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                          ^^^^^^^^^^^^^^^
 
 error: aborting due to 10 previous errors
diff --git a/tests/ui/implicit_return.rs b/tests/ui/implicit_return.rs
new file mode 100644 (file)
index 0000000..d1c63ca
--- /dev/null
@@ -0,0 +1,89 @@
+#![warn(clippy::implicit_return)]
+
+fn test_end_of_fn() -> bool {
+    if true {
+        // no error!
+        return true;
+    }
+    true
+}
+
+#[allow(clippy::needless_bool)]
+fn test_if_block() -> bool {
+    if true {
+        true
+    } else {
+        false
+    }
+}
+
+#[allow(clippy::match_bool)]
+#[rustfmt::skip]
+fn test_match(x: bool) -> bool {
+    match x {
+        true => false,
+        false => { true },
+    }
+}
+
+#[allow(clippy::match_bool, clippy::needless_return)]
+fn test_match_with_unreachable(x: bool) -> bool {
+    match x {
+        true => return false,
+        false => unreachable!(),
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop() -> bool {
+    loop {
+        break true;
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop_with_block() -> bool {
+    loop {
+        {
+            break true;
+        }
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn test_loop_with_nests() -> bool {
+    loop {
+        if true {
+            break true;
+        } else {
+            let _ = true;
+        }
+    }
+}
+
+#[allow(clippy::redundant_pattern_matching)]
+fn test_loop_with_if_let() -> bool {
+    loop {
+        if let Some(x) = Some(true) {
+            return x;
+        }
+    }
+}
+
+fn test_closure() {
+    #[rustfmt::skip]
+    let _ = || { true };
+    let _ = || true;
+}
+
+fn main() {
+    let _ = test_end_of_fn();
+    let _ = test_if_block();
+    let _ = test_match(true);
+    let _ = test_match_with_unreachable(true);
+    let _ = test_loop();
+    let _ = test_loop_with_block();
+    let _ = test_loop_with_nests();
+    let _ = test_loop_with_if_let();
+    test_closure();
+}
diff --git a/tests/ui/implicit_return.stderr b/tests/ui/implicit_return.stderr
new file mode 100644 (file)
index 0000000..98b588f
--- /dev/null
@@ -0,0 +1,64 @@
+error: missing return statement
+  --> $DIR/implicit_return.rs:8:5
+   |
+LL |     true
+   |     ^^^^ help: add `return` as shown: `return true`
+   |
+   = note: `-D clippy::implicit-return` implied by `-D warnings`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:14:9
+   |
+LL |         true
+   |         ^^^^ help: add `return` as shown: `return true`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:16:9
+   |
+LL |         false
+   |         ^^^^^ help: add `return` as shown: `return false`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:24:17
+   |
+LL |         true => false,
+   |                 ^^^^^ help: add `return` as shown: `return false`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:25:20
+   |
+LL |         false => { true },
+   |                    ^^^^ help: add `return` as shown: `return true`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:40:9
+   |
+LL |         break true;
+   |         ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:48:13
+   |
+LL |             break true;
+   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:57:13
+   |
+LL |             break true;
+   |             ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:75:18
+   |
+LL |     let _ = || { true };
+   |                  ^^^^ help: add `return` as shown: `return true`
+
+error: missing return statement
+  --> $DIR/implicit_return.rs:76:16
+   |
+LL |     let _ = || true;
+   |                ^^^^ help: add `return` as shown: `return true`
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/inconsistent_digit_grouping.fixed b/tests/ui/inconsistent_digit_grouping.fixed
new file mode 100644 (file)
index 0000000..f25be70
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+#[warn(clippy::inconsistent_digit_grouping)]
+#[allow(unused_variables, clippy::excessive_precision)]
+fn main() {
+    let good = (
+        123,
+        1_234,
+        1_2345_6789,
+        123_f32,
+        1_234.12_f32,
+        1_234.123_4_f32,
+        1.123_456_7_f32,
+    );
+    let bad = (123_456, 12_345_678, 1_234_567, 1_234.567_8_f32, 1.234_567_8_f32);
+}
index ed6dc06edb17db1eabc7cb1c6329be062c1ff891..206fac8d3e3fd9469d663fc4efcddc6297c07b2e 100644 (file)
@@ -1,8 +1,15 @@
-
-
-#[warn(inconsistent_digit_grouping)]
-#[allow(unused_variables)]
+// run-rustfix
+#[warn(clippy::inconsistent_digit_grouping)]
+#[allow(unused_variables, clippy::excessive_precision)]
 fn main() {
-    let good = (123, 1_234, 1_2345_6789, 123_f32, 1_234.12_f32, 1_234.123_4_f32, 1.123_456_7_f32);
+    let good = (
+        123,
+        1_234,
+        1_2345_6789,
+        123_f32,
+        1_234.12_f32,
+        1_234.123_4_f32,
+        1.123_456_7_f32,
+    );
     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
 }
index 4d30529d820af40d2330e22a3578427b5695200d..9fc1f424dc6ae82a4ec3e5c30f84648c7d7e37c4 100644 (file)
@@ -1,34 +1,34 @@
 error: digits grouped inconsistently by underscores
--> $DIR/inconsistent_digit_grouping.rs:7:16
-  |
-7 |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
-  |                ^^^^^^^^ help: consider: `123_456`
-  |
-  = note: `-D inconsistent-digit-grouping` implied by `-D warnings`
 --> $DIR/inconsistent_digit_grouping.rs:14:16
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                ^^^^^^^^ help: consider: `123_456`
+   |
+   = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
 
 error: digits grouped inconsistently by underscores
--> $DIR/inconsistent_digit_grouping.rs:7:26
-  |
-7 |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
-  |                          ^^^^^^^^^^ help: consider: `12_345_678`
 --> $DIR/inconsistent_digit_grouping.rs:14:26
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                          ^^^^^^^^^^ help: consider: `12_345_678`
 
 error: digits grouped inconsistently by underscores
--> $DIR/inconsistent_digit_grouping.rs:7:38
-  |
-7 |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
-  |                                      ^^^^^^^^ help: consider: `1_234_567`
 --> $DIR/inconsistent_digit_grouping.rs:14:38
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                                      ^^^^^^^^ help: consider: `1_234_567`
 
 error: digits grouped inconsistently by underscores
--> $DIR/inconsistent_digit_grouping.rs:7:48
-  |
-7 |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
-  |                                                ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32`
 --> $DIR/inconsistent_digit_grouping.rs:14:48
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                                                ^^^^^^^^^^^^^^ help: consider: `1_234.567_8_f32`
 
 error: digits grouped inconsistently by underscores
--> $DIR/inconsistent_digit_grouping.rs:7:64
-  |
-7 |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
-  |                                                                ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32`
 --> $DIR/inconsistent_digit_grouping.rs:14:64
+   |
+LL |     let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32);
+   |                                                                ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32`
 
 error: aborting due to 5 previous errors
 
index e39dc92367c8ecc5c9ddfa3e9a518da13f237e20..f0bd39c025428848bfc8bdd3c40ba1af63c6cf45 100644 (file)
@@ -1,7 +1,7 @@
 #![feature(plugin)]
-#![warn(indexing_slicing)]
-#![warn(out_of_bounds_indexing)]
-#![allow(no_effect, unnecessary_operation)]
+#![warn(clippy::indexing_slicing)]
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
 
 fn main() {
     let x = [1, 2, 3, 4];
@@ -79,4 +79,9 @@ fn main() {
     x[M]; // Ok, should not produce stderr.
     v[N];
     v[M];
+
+    // issue 3102
+    let num = 1;
+    &x[num..10]; // should trigger out of bounds error
+    &x[10..num]; // should trigger out of bounds error
 }
index ee11dce6d1c2c164e917e9d10df577be72245d31..129fec0e97c1a75773b025012238eff65c9b0b6b 100644 (file)
@@ -1,16 +1,42 @@
+error: index out of bounds: the len is 4 but the index is 4
+  --> $DIR/indexing_slicing.rs:16:5
+   |
+LL |     x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^
+   |
+   = note: #[deny(const_err)] on by default
+
+error: index out of bounds: the len is 4 but the index is 8
+  --> $DIR/indexing_slicing.rs:17:5
+   |
+LL |     x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^^^^^^
+
+error: index out of bounds: the len is 0 but the index is 0
+  --> $DIR/indexing_slicing.rs:47:5
+   |
+LL |     empty[0]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^^^^^
+
+error: index out of bounds: the len is 4 but the index is 15
+  --> $DIR/indexing_slicing.rs:78:5
+   |
+LL |     x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
+   |     ^^^^
+
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:11:5
    |
-11 |     x[index];
+LL |     x[index];
    |     ^^^^^^^^
    |
-   = note: `-D indexing-slicing` implied by `-D warnings`
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:12:6
    |
-12 |     &x[index..];
+LL |     &x[index..];
    |      ^^^^^^^^^^
    |
    = help: Consider using `.get(n..)` or .get_mut(n..)` instead
@@ -18,7 +44,7 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:13:6
    |
-13 |     &x[..index];
+LL |     &x[..index];
    |      ^^^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
@@ -26,7 +52,7 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:14:6
    |
-14 |     &x[index_from..index_to];
+LL |     &x[index_from..index_to];
    |      ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
@@ -34,7 +60,7 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:15:6
    |
-15 |     &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
+LL |     &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
@@ -42,67 +68,67 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:15:6
    |
-15 |     &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
+LL |     &x[index_from..][..index_to]; // Two lint reports, one for [index_from..] and another for [..index_to].
    |      ^^^^^^^^^^^^^^^
    |
    = help: Consider using `.get(n..)` or .get_mut(n..)` instead
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:18:6
+  --> $DIR/indexing_slicing.rs:18:11
    |
-18 |     &x[..=4];
-   |      ^^^^^^^
+LL |     &x[..=4];
+   |           ^
    |
-   = note: `-D out-of-bounds-indexing` implied by `-D warnings`
+   = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:19:6
+  --> $DIR/indexing_slicing.rs:19:11
    |
-19 |     &x[1..5];
-   |      ^^^^^^^
+LL |     &x[1..5];
+   |           ^
 
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:20:6
    |
-20 |     &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10].
+LL |     &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10].
    |      ^^^^^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:20:6
+  --> $DIR/indexing_slicing.rs:20:8
    |
-20 |     &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10].
-   |      ^^^^^^
+LL |     &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10].
+   |        ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:21:6
+  --> $DIR/indexing_slicing.rs:21:8
    |
-21 |     &x[5..];
-   |      ^^^^^^
+LL |     &x[5..];
+   |        ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:22:6
+  --> $DIR/indexing_slicing.rs:22:10
    |
-22 |     &x[..5];
-   |      ^^^^^^
+LL |     &x[..5];
+   |          ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:23:6
+  --> $DIR/indexing_slicing.rs:23:8
    |
-23 |     &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>();
-   |      ^^^^^^
+LL |     &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>();
+   |        ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:24:6
+  --> $DIR/indexing_slicing.rs:24:12
    |
-24 |     &x[0..=4];
-   |      ^^^^^^^^
+LL |     &x[0..=4];
+   |            ^
 
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:25:6
    |
-25 |     &x[0..][..3];
+LL |     &x[0..][..3];
    |      ^^^^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
@@ -110,7 +136,7 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:26:6
    |
-26 |     &x[1..][..5];
+LL |     &x[1..][..5];
    |      ^^^^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
@@ -118,7 +144,7 @@ error: slicing may panic.
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:39:5
    |
-39 |     y[0];
+LL |     y[0];
    |     ^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
@@ -126,7 +152,7 @@ error: indexing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:40:6
    |
-40 |     &y[1..2];
+LL |     &y[1..2];
    |      ^^^^^^^
    |
    = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
@@ -134,7 +160,7 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:41:6
    |
-41 |     &y[0..=4];
+LL |     &y[0..=4];
    |      ^^^^^^^^
    |
    = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
@@ -142,57 +168,57 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:42:6
    |
-42 |     &y[..=4];
+LL |     &y[..=4];
    |      ^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:48:6
+  --> $DIR/indexing_slicing.rs:48:12
    |
-48 |     &empty[1..5];
-   |      ^^^^^^^^^^^
+LL |     &empty[1..5];
+   |            ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:49:6
+  --> $DIR/indexing_slicing.rs:49:16
    |
-49 |     &empty[0..=4];
-   |      ^^^^^^^^^^^^
+LL |     &empty[0..=4];
+   |                ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:50:6
+  --> $DIR/indexing_slicing.rs:50:15
    |
-50 |     &empty[..=4];
-   |      ^^^^^^^^^^^
+LL |     &empty[..=4];
+   |               ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:51:6
+  --> $DIR/indexing_slicing.rs:51:12
    |
-51 |     &empty[1..];
-   |      ^^^^^^^^^^
+LL |     &empty[1..];
+   |            ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:52:6
+  --> $DIR/indexing_slicing.rs:52:14
    |
-52 |     &empty[..4];
-   |      ^^^^^^^^^^
+LL |     &empty[..4];
+   |              ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:53:6
+  --> $DIR/indexing_slicing.rs:53:16
    |
-53 |     &empty[0..=0];
-   |      ^^^^^^^^^^^^
+LL |     &empty[0..=0];
+   |                ^
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:54:6
+  --> $DIR/indexing_slicing.rs:54:15
    |
-54 |     &empty[..=0];
-   |      ^^^^^^^^^^^
+LL |     &empty[..=0];
+   |               ^
 
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:62:5
    |
-62 |     v[0];
+LL |     v[0];
    |     ^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
@@ -200,7 +226,7 @@ error: indexing may panic.
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:63:5
    |
-63 |     v[10];
+LL |     v[10];
    |     ^^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
@@ -208,7 +234,7 @@ error: indexing may panic.
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:64:5
    |
-64 |     v[1 << 3];
+LL |     v[1 << 3];
    |     ^^^^^^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
@@ -216,7 +242,7 @@ error: indexing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:65:6
    |
-65 |     &v[10..100];
+LL |     &v[10..100];
    |      ^^^^^^^^^^
    |
    = help: Consider using `.get(n..m)` or `.get_mut(n..m)` instead
@@ -224,21 +250,21 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:66:6
    |
-66 |     &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
+LL |     &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
    |      ^^^^^^^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
 
 error: range is out of bounds
-  --> $DIR/indexing_slicing.rs:66:6
+  --> $DIR/indexing_slicing.rs:66:8
    |
-66 |     &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
-   |      ^^^^^^^
+LL |     &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
+   |        ^^
 
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:67:6
    |
-67 |     &v[10..];
+LL |     &v[10..];
    |      ^^^^^^^
    |
    = help: Consider using `.get(n..)` or .get_mut(n..)` instead
@@ -246,7 +272,7 @@ error: slicing may panic.
 error: slicing may panic.
   --> $DIR/indexing_slicing.rs:68:6
    |
-68 |     &v[..100];
+LL |     &v[..100];
    |      ^^^^^^^^
    |
    = help: Consider using `.get(..n)`or `.get_mut(..n)` instead
@@ -254,7 +280,7 @@ error: slicing may panic.
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:80:5
    |
-80 |     v[N];
+LL |     v[N];
    |     ^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
@@ -262,10 +288,22 @@ error: indexing may panic.
 error: indexing may panic.
   --> $DIR/indexing_slicing.rs:81:5
    |
-81 |     v[M];
+LL |     v[M];
    |     ^^^^
    |
    = help: Consider using `.get(n)` or `.get_mut(n)` instead
 
-error: aborting due to 37 previous errors
+error: range is out of bounds
+  --> $DIR/indexing_slicing.rs:85:13
+   |
+LL |     &x[num..10]; // should trigger out of bounds error
+   |             ^^
+
+error: range is out of bounds
+  --> $DIR/indexing_slicing.rs:86:8
+   |
+LL |     &x[10..num]; // should trigger out of bounds error
+   |        ^^
+
+error: aborting due to 43 previous errors
 
diff --git a/tests/ui/infallible_destructuring_match.fixed b/tests/ui/infallible_destructuring_match.fixed
new file mode 100644 (file)
index 0000000..f16f0fd
--- /dev/null
@@ -0,0 +1,79 @@
+// run-rustfix
+#![feature(exhaustive_patterns, never_type)]
+#![allow(dead_code, unreachable_code, unused_variables)]
+#![allow(clippy::let_and_return)]
+
+enum SingleVariantEnum {
+    Variant(i32),
+}
+
+struct TupleStruct(i32);
+
+enum EmptyEnum {}
+
+fn infallible_destructuring_match_enum() {
+    let wrapper = SingleVariantEnum::Variant(0);
+
+    // This should lint!
+    let SingleVariantEnum::Variant(data) = wrapper;
+
+    // This shouldn't!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        SingleVariantEnum::Variant(i) => -1,
+    };
+
+    let SingleVariantEnum::Variant(data) = wrapper;
+}
+
+fn infallible_destructuring_match_struct() {
+    let wrapper = TupleStruct(0);
+
+    // This should lint!
+    let TupleStruct(data) = wrapper;
+
+    // This shouldn't!
+    let data = match wrapper {
+        TupleStruct(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        TupleStruct(i) => -1,
+    };
+
+    let TupleStruct(data) = wrapper;
+}
+
+fn never_enum() {
+    let wrapper: Result<i32, !> = Ok(23);
+
+    // This should lint!
+    let Ok(data) = wrapper;
+
+    // This shouldn't!
+    let data = match wrapper {
+        Ok(_) => -1,
+    };
+
+    // Neither should this!
+    let data = match wrapper {
+        Ok(i) => -1,
+    };
+
+    let Ok(data) = wrapper;
+}
+
+impl EmptyEnum {
+    fn match_on(&self) -> ! {
+        // The lint shouldn't pick this up, as `let` won't work here!
+        let data = match *self {};
+        data
+    }
+}
+
+fn main() {}
index 6f3d7a3ff2ba83fdc945970c04e1232147fe0889..a4823ad60ad3dc9496a155bb7a16c7e71c3b1541 100644 (file)
@@ -1,5 +1,7 @@
+// run-rustfix
 #![feature(exhaustive_patterns, never_type)]
-#![allow(let_and_return)]
+#![allow(dead_code, unreachable_code, unused_variables)]
+#![allow(clippy::let_and_return)]
 
 enum SingleVariantEnum {
     Variant(i32),
index 8ee73bbfde8d8eca5aa5783dfecc8bbbc577dc94..e3693d44e9a1397ce724eab08d0a4df3d315520f 100644 (file)
@@ -1,27 +1,27 @@
 error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let`
-  --> $DIR/infallible_destructuring_match.rs:16:5
+  --> $DIR/infallible_destructuring_match.rs:18:5
    |
-16 | /     let data = match wrapper {
-17 | |         SingleVariantEnum::Variant(i) => i,
-18 | |     };
+LL | /     let data = match wrapper {
+LL | |         SingleVariantEnum::Variant(i) => i,
+LL | |     };
    | |______^ help: try this: `let SingleVariantEnum::Variant(data) = wrapper;`
    |
-   = note: `-D infallible-destructuring-match` implied by `-D warnings`
+   = note: `-D clippy::infallible-destructuring-match` implied by `-D warnings`
 
 error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let`
-  --> $DIR/infallible_destructuring_match.rs:37:5
+  --> $DIR/infallible_destructuring_match.rs:39:5
    |
-37 | /     let data = match wrapper {
-38 | |         TupleStruct(i) => i,
-39 | |     };
+LL | /     let data = match wrapper {
+LL | |         TupleStruct(i) => i,
+LL | |     };
    | |______^ help: try this: `let TupleStruct(data) = wrapper;`
 
 error: you seem to be trying to use match to destructure a single infallible pattern. Consider using `let`
-  --> $DIR/infallible_destructuring_match.rs:58:5
+  --> $DIR/infallible_destructuring_match.rs:60:5
    |
-58 | /     let data = match wrapper {
-59 | |         Ok(i) => i,
-60 | |     };
+LL | /     let data = match wrapper {
+LL | |         Ok(i) => i,
+LL | |     };
    | |______^ help: try this: `let Ok(data) = wrapper;`
 
 error: aborting due to 3 previous errors
index 2e2ccd9f1ae87706f3bb41e87c785e98081a7757..c324eb957776ce4835d843e6b11c224341fbc75f 100644 (file)
@@ -1,29 +1,41 @@
-#![feature(iterator_for_each)]
-
 use std::iter::repeat;
-#[allow(trivially_copy_pass_by_ref)]
-fn square_is_lower_64(x: &u32) -> bool { x * x < 64 }
+#[allow(clippy::trivially_copy_pass_by_ref)]
+fn square_is_lower_64(x: &u32) -> bool {
+    x * x < 64
+}
 
-#[allow(maybe_infinite_iter)]
-#[deny(infinite_iter)]
+#[allow(clippy::maybe_infinite_iter)]
+#[deny(clippy::infinite_iter)]
 fn infinite_iters() {
     repeat(0_u8).collect::<Vec<_>>(); // infinite iter
     (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter
     (0..8_u64).chain(0..).max(); // infinite iter
-    (0_usize..).chain([0usize, 1, 2].iter().cloned()).skip_while(|x| *x != 42).min(); // infinite iter
-    (0..8_u32).rev().cycle().map(|x| x + 1_u32).for_each(|x| println!("{}", x)); // infinite iter
+    (0_usize..)
+        .chain([0usize, 1, 2].iter().cloned())
+        .skip_while(|x| *x != 42)
+        .min(); // infinite iter
+    (0..8_u32)
+        .rev()
+        .cycle()
+        .map(|x| x + 1_u32)
+        .for_each(|x| println!("{}", x)); // infinite iter
     (0..3_u32).flat_map(|x| x..).sum::<u32>(); // infinite iter
-    (0_usize..).flat_map(|x| 0..x).product::<usize>();  // infinite iter
+    (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter
     (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter
     (0..42_u64).by_ref().last(); // not an infinite, because ranges are double-ended
     (0..).next(); // iterator is not exhausted
 }
 
-#[deny(maybe_infinite_iter)]
+#[deny(clippy::maybe_infinite_iter)]
 fn potential_infinite_iters() {
     (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter
     repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter
-    (1..).scan(0, |state, x| { *state += x; Some(*state) }).min(); // maybe infinite iter
+    (1..)
+        .scan(0, |state, x| {
+            *state += x;
+            Some(*state)
+        })
+        .min(); // maybe infinite iter
     (0..).find(|x| *x == 24); // maybe infinite iter
     (0..).position(|x| x == 24); // maybe infinite iter
     (0..).any(|x| x == 24); // maybe infinite iter
@@ -37,3 +49,22 @@ fn main() {
     infinite_iters();
     potential_infinite_iters();
 }
+
+mod finite_collect {
+    use std::collections::HashSet;
+    use std::iter::FromIterator;
+
+    struct C;
+    impl FromIterator<i32> for C {
+        fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
+            C
+        }
+    }
+
+    fn check_collect() {
+        let _: HashSet<i32> = (0..).collect(); // Infinite iter
+
+        // Some data structures don't collect infinitely, such as `ArrayVec`
+        let _: C = (0..).collect();
+    }
+}
index f79db778488450be59bd5c6af100e049b1163c6c..564c2b43778b6581769272e790a45ee519b2c962 100644 (file)
 error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator
   --> $DIR/infinite_iter.rs:10:5
    |
-10 |     repeat(0_u8).collect::<Vec<_>>(); // infinite iter
+LL |     repeat(0_u8).collect::<Vec<_>>(); // infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D unused-collect` implied by `-D warnings`
+   = note: `-D clippy::unused-collect` implied by `-D warnings`
 
 error: infinite iteration detected
   --> $DIR/infinite_iter.rs:10:5
    |
-10 |     repeat(0_u8).collect::<Vec<_>>(); // infinite iter
+LL |     repeat(0_u8).collect::<Vec<_>>(); // infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: lint level defined here
   --> $DIR/infinite_iter.rs:8:8
    |
-8  | #[deny(infinite_iter)]
-   |        ^^^^^^^^^^^^^
+LL | #[deny(clippy::infinite_iter)]
+   |        ^^^^^^^^^^^^^^^^^^^^^
 
 error: infinite iteration detected
   --> $DIR/infinite_iter.rs:11:5
    |
-11 |     (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter
+LL |     (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: infinite iteration detected
   --> $DIR/infinite_iter.rs:12:5
    |
-12 |     (0..8_u64).chain(0..).max(); // infinite iter
+LL |     (0..8_u64).chain(0..).max(); // infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: infinite iteration detected
-  --> $DIR/infinite_iter.rs:14:5
+  --> $DIR/infinite_iter.rs:17:5
    |
-14 |     (0..8_u32).rev().cycle().map(|x| x + 1_u32).for_each(|x| println!("{}", x)); // infinite iter
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     (0..8_u32)
+LL | |         .rev()
+LL | |         .cycle()
+LL | |         .map(|x| x + 1_u32)
+LL | |         .for_each(|x| println!("{}", x)); // infinite iter
+   | |________________________________________^
 
 error: infinite iteration detected
-  --> $DIR/infinite_iter.rs:16:5
+  --> $DIR/infinite_iter.rs:23:5
    |
-16 |     (0_usize..).flat_map(|x| 0..x).product::<usize>();  // infinite iter
+LL |     (0_usize..).flat_map(|x| 0..x).product::<usize>(); // infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: infinite iteration detected
-  --> $DIR/infinite_iter.rs:17:5
+  --> $DIR/infinite_iter.rs:24:5
    |
-17 |     (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter
+LL |     (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:24:5
+  --> $DIR/infinite_iter.rs:31:5
    |
-24 |     (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter
+LL |     (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: lint level defined here
-  --> $DIR/infinite_iter.rs:22:8
+  --> $DIR/infinite_iter.rs:29:8
    |
-22 | #[deny(maybe_infinite_iter)]
-   |        ^^^^^^^^^^^^^^^^^^^
+LL | #[deny(clippy::maybe_infinite_iter)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:25:5
+  --> $DIR/infinite_iter.rs:32:5
    |
-25 |     repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter
+LL |     repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:26:5
-   |
-26 |     (1..).scan(0, |state, x| { *state += x; Some(*state) }).min(); // maybe infinite iter
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/infinite_iter.rs:33:5
+   |
+LL | /     (1..)
+LL | |         .scan(0, |state, x| {
+LL | |             *state += x;
+LL | |             Some(*state)
+LL | |         })
+LL | |         .min(); // maybe infinite iter
+   | |______________^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:27:5
+  --> $DIR/infinite_iter.rs:39:5
    |
-27 |     (0..).find(|x| *x == 24); // maybe infinite iter
+LL |     (0..).find(|x| *x == 24); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:28:5
+  --> $DIR/infinite_iter.rs:40:5
    |
-28 |     (0..).position(|x| x == 24); // maybe infinite iter
+LL |     (0..).position(|x| x == 24); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:29:5
+  --> $DIR/infinite_iter.rs:41:5
    |
-29 |     (0..).any(|x| x == 24); // maybe infinite iter
+LL |     (0..).any(|x| x == 24); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: possible infinite iteration detected
-  --> $DIR/infinite_iter.rs:30:5
+  --> $DIR/infinite_iter.rs:42:5
    |
-30 |     (0..).all(|x| x == 24); // maybe infinite iter
+LL |     (0..).all(|x| x == 24); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:65:31
+   |
+LL |         let _: HashSet<i32> = (0..).collect(); // Infinite iter
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: #[deny(clippy::infinite_iter)] on by default
+
+error: aborting due to 15 previous errors
 
index 9e801911602c79b50d924742646b651dd307ee28..4df218aa4f31385f500f27a9269ef7d0484cff50 100644 (file)
@@ -1,13 +1,22 @@
-#![allow(trivially_copy_pass_by_ref)]
+#![allow(clippy::trivially_copy_pass_by_ref)]
 
+fn fn_val(i: i32) -> i32 {
+    unimplemented!()
+}
+fn fn_constref(i: &i32) -> i32 {
+    unimplemented!()
+}
+fn fn_mutref(i: &mut i32) {
+    unimplemented!()
+}
+fn fooi() -> i32 {
+    unimplemented!()
+}
+fn foob() -> bool {
+    unimplemented!()
+}
 
-fn fn_val(i: i32) -> i32 { unimplemented!() }
-fn fn_constref(i: &i32) -> i32 { unimplemented!() }
-fn fn_mutref(i: &mut i32) { unimplemented!() }
-fn fooi() -> i32 { unimplemented!() }
-fn foob() -> bool { unimplemented!() }
-
-#[allow(many_single_char_names)]
+#[allow(clippy::many_single_char_names)]
 fn immutable_condition() {
     // Should warn when all vars mentioned are immutable
     let y = 0;
@@ -131,12 +140,15 @@ fn consts() {
 
 use std::cell::Cell;
 
-fn maybe_i_mutate(i: &Cell<bool>) { unimplemented!() }
+fn maybe_i_mutate(i: &Cell<bool>) {
+    unimplemented!()
+}
 
 fn internally_mutable() {
     let b = Cell::new(true);
 
-    while b.get() {       // b cannot be silently coerced to `bool`
+    while b.get() {
+        // b cannot be silently coerced to `bool`
         maybe_i_mutate(&b);
         println!("OK - Method call within condition");
     }
index 26ec9582fb403e73c6e2ec4bdd05804bd8a6443f..a3fc591c1b1617dc7a5eb7765b6951743d565e4a 100644 (file)
@@ -1,58 +1,58 @@
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:14:11
+  --> $DIR/infinite_loop.rs:23:11
    |
-14 |     while y < 10 {
+LL |     while y < 10 {
    |           ^^^^^^
    |
-   = note: #[deny(while_immutable_condition)] on by default
+   = note: #[deny(clippy::while_immutable_condition)] on by default
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:19:11
+  --> $DIR/infinite_loop.rs:28:11
    |
-19 |     while y < 10 && x < 3 {
+LL |     while y < 10 && x < 3 {
    |           ^^^^^^^^^^^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:26:11
+  --> $DIR/infinite_loop.rs:35:11
    |
-26 |     while !cond {
+LL |     while !cond {
    |           ^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:70:11
+  --> $DIR/infinite_loop.rs:79:11
    |
-70 |     while i < 3 {
+LL |     while i < 3 {
    |           ^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:75:11
+  --> $DIR/infinite_loop.rs:84:11
    |
-75 |     while i < 3 && j > 0 {
+LL |     while i < 3 && j > 0 {
    |           ^^^^^^^^^^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:79:11
+  --> $DIR/infinite_loop.rs:88:11
    |
-79 |     while i < 3 {
+LL |     while i < 3 {
    |           ^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:94:11
+  --> $DIR/infinite_loop.rs:103:11
    |
-94 |     while i < 3 {
+LL |     while i < 3 {
    |           ^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-  --> $DIR/infinite_loop.rs:99:11
+  --> $DIR/infinite_loop.rs:108:11
    |
-99 |     while i < 3 {
+LL |     while i < 3 {
    |           ^^^^^
 
 error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
-   --> $DIR/infinite_loop.rs:162:15
-    |
-162 |         while self.count < n {
-    |               ^^^^^^^^^^^^^^
+  --> $DIR/infinite_loop.rs:174:15
+   |
+LL |         while self.count < n {
+   |               ^^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
index 76e50e56780cd0b49478de40b158f8b5308e316f..af81feaa374a7cef918faf9630a6974c25ddb983 100644 (file)
@@ -1,22 +1,18 @@
-
-
-
-#![warn(inline_fn_without_body)]
-#![allow(inline_always)]
+#![warn(clippy::inline_fn_without_body)]
+#![allow(clippy::inline_always)]
 
 trait Foo {
     #[inline]
     fn default_inline();
 
-    #[inline(always)]fn always_inline();
+    #[inline(always)]
+    fn always_inline();
 
     #[inline(never)]
     fn never_inline();
 
     #[inline]
-    fn has_body() {
-    }
+    fn has_body() {}
 }
 
-fn main() {
-}
+fn main() {}
index 2b466b6861030ade207abb0759dd52bdbc22ab5e..87d2da71280d88cbd8ba84c20a60b4364da9fae2 100644 (file)
@@ -1,25 +1,27 @@
 error: use of `#[inline]` on trait method `default_inline` which has no body
--> $DIR/inline_fn_without_body.rs:8:5
-  |
-8 |       #[inline]
-  |  _____-^^^^^^^^
-9 | |     fn default_inline();
-  | |____- help: remove
-  |
-  = note: `-D inline-fn-without-body` implied by `-D warnings`
 --> $DIR/inline_fn_without_body.rs:5:5
+   |
+LL |       #[inline]
+   |  _____-^^^^^^^^
+LL | |     fn default_inline();
+   | |____- help: remove
+   |
+   = note: `-D clippy::inline-fn-without-body` implied by `-D warnings`
 
 error: use of `#[inline]` on trait method `always_inline` which has no body
-  --> $DIR/inline_fn_without_body.rs:11:5
+  --> $DIR/inline_fn_without_body.rs:8:5
    |
-11 |     #[inline(always)]fn always_inline();
-   |     ^^^^^^^^^^^^^^^^^ help: remove
+LL |       #[inline(always)]
+   |  _____-^^^^^^^^^^^^^^^^
+LL | |     fn always_inline();
+   | |____- help: remove
 
 error: use of `#[inline]` on trait method `never_inline` which has no body
-  --> $DIR/inline_fn_without_body.rs:13:5
+  --> $DIR/inline_fn_without_body.rs:11:5
    |
-13 |       #[inline(never)]
+LL |       #[inline(never)]
    |  _____-^^^^^^^^^^^^^^^
-14 | |     fn never_inline();
+LL | |     fn never_inline();
    | |____- help: remove
 
 error: aborting due to 3 previous errors
index a9e059f4a3eddde5fde2901c18f6cc71b7845342..42d8045244f385d398d7dd360e332f1e1ea37718 100644 (file)
@@ -1,12 +1,9 @@
-
-
-
-#[allow(no_effect, unnecessary_operation)]
-#[warn(int_plus_one)]
+#[allow(clippy::no_effect, clippy::unnecessary_operation)]
+#[warn(clippy::int_plus_one)]
 fn main() {
     let x = 1i32;
     let y = 0i32;
-    
+
     x >= y + 1;
     y + 1 <= x;
 
index deecaffa1cf1235a4b014e5f33abfaf55f630a29..4a783e50c672884c1cda30861671aa298c2e5a86 100644 (file)
@@ -1,43 +1,43 @@
 error: Unnecessary `>= y + 1` or `x - 1 >=`
-  --> $DIR/int_plus_one.rs:10:5
+  --> $DIR/int_plus_one.rs:7:5
    |
-10 |     x >= y + 1;
+LL |     x >= y + 1;
    |     ^^^^^^^^^^
    |
-   = note: `-D int-plus-one` implied by `-D warnings`
+   = note: `-D clippy::int-plus-one` implied by `-D warnings`
 help: change `>= y + 1` to `> y` as shown
    |
-10 |     x > y;
+LL |     x > y;
    |     ^^^^^
 
 error: Unnecessary `>= y + 1` or `x - 1 >=`
-  --> $DIR/int_plus_one.rs:11:5
+  --> $DIR/int_plus_one.rs:8:5
    |
-11 |     y + 1 <= x;
+LL |     y + 1 <= x;
    |     ^^^^^^^^^^
 help: change `>= y + 1` to `> y` as shown
    |
-11 |     y < x;
+LL |     y < x;
    |     ^^^^^
 
 error: Unnecessary `>= y + 1` or `x - 1 >=`
-  --> $DIR/int_plus_one.rs:13:5
+  --> $DIR/int_plus_one.rs:10:5
    |
-13 |     x - 1 >= y;
+LL |     x - 1 >= y;
    |     ^^^^^^^^^^
 help: change `>= y + 1` to `> y` as shown
    |
-13 |     x > y;
+LL |     x > y;
    |     ^^^^^
 
 error: Unnecessary `>= y + 1` or `x - 1 >=`
-  --> $DIR/int_plus_one.rs:14:5
+  --> $DIR/int_plus_one.rs:11:5
    |
-14 |     y <= x - 1;
+LL |     y <= x - 1;
    |     ^^^^^^^^^^
 help: change `>= y + 1` to `> y` as shown
    |
-14 |     y < x;
+LL |     y < x;
    |     ^^^^^
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed
new file mode 100644 (file)
index 0000000..f5342be
--- /dev/null
@@ -0,0 +1,46 @@
+// run-rustfix
+#![allow(clippy::useless_vec)]
+#![warn(clippy::into_iter_on_ref)]
+#![deny(clippy::into_iter_on_array)]
+
+struct X;
+use std::collections::*;
+
+fn main() {
+    for _ in &[1, 2, 3] {}
+    for _ in vec![X, X] {}
+    for _ in &vec![X, X] {}
+    for _ in [1, 2, 3].iter() {} //~ ERROR equivalent to .iter()
+
+    let _ = [1, 2, 3].iter(); //~ ERROR equivalent to .iter()
+    let _ = vec![1, 2, 3].into_iter();
+    let _ = (&vec![1, 2, 3]).iter(); //~ WARN equivalent to .iter()
+    let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ WARN equivalent to .iter()
+    let _ = std::rc::Rc::from(&[X][..]).iter(); //~ WARN equivalent to .iter()
+    let _ = std::sync::Arc::from(&[X][..]).iter(); //~ WARN equivalent to .iter()
+
+    let _ = (&&&&&&&[1, 2, 3]).iter(); //~ ERROR equivalent to .iter()
+    let _ = (&&&&mut &&&[1, 2, 3]).iter(); //~ ERROR equivalent to .iter()
+    let _ = (&mut &mut &mut [1, 2, 3]).iter_mut(); //~ ERROR equivalent to .iter_mut()
+
+    let _ = (&Some(4)).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Some(5)).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Ok::<_, i32>(6)).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Err::<i32, _>(7)).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Vec::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Vec::<i32>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&BTreeMap::<i32, u64>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut BTreeMap::<i32, u64>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&VecDeque::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut VecDeque::<i32>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&LinkedList::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut LinkedList::<i32>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+    let _ = (&HashMap::<i32, u64>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut HashMap::<i32, u64>::new()).iter_mut(); //~ WARN equivalent to .iter_mut()
+
+    let _ = (&BTreeSet::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&BinaryHeap::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = (&HashSet::<i32>::new()).iter(); //~ WARN equivalent to .iter()
+    let _ = std::path::Path::new("12/34").iter(); //~ WARN equivalent to .iter()
+    let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR equivalent to .iter()
+}
diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs
new file mode 100644 (file)
index 0000000..5ec64dc
--- /dev/null
@@ -0,0 +1,46 @@
+// run-rustfix
+#![allow(clippy::useless_vec)]
+#![warn(clippy::into_iter_on_ref)]
+#![deny(clippy::into_iter_on_array)]
+
+struct X;
+use std::collections::*;
+
+fn main() {
+    for _ in &[1, 2, 3] {}
+    for _ in vec![X, X] {}
+    for _ in &vec![X, X] {}
+    for _ in [1, 2, 3].into_iter() {} //~ ERROR equivalent to .iter()
+
+    let _ = [1, 2, 3].into_iter(); //~ ERROR equivalent to .iter()
+    let _ = vec![1, 2, 3].into_iter();
+    let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
+    let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
+    let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+    let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+
+    let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+    let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+    let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
+
+    let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+    let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+
+    let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+    let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
+    let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
+}
diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr
new file mode 100644 (file)
index 0000000..931e488
--- /dev/null
@@ -0,0 +1,178 @@
+error: this .into_iter() call is equivalent to .iter() and will not move the array
+  --> $DIR/into_iter_on_ref.rs:13:24
+   |
+LL |     for _ in [1, 2, 3].into_iter() {} //~ ERROR equivalent to .iter()
+   |                        ^^^^^^^^^ help: call directly: `iter`
+   |
+note: lint level defined here
+  --> $DIR/into_iter_on_ref.rs:4:9
+   |
+LL | #![deny(clippy::into_iter_on_array)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this .into_iter() call is equivalent to .iter() and will not move the array
+  --> $DIR/into_iter_on_ref.rs:15:23
+   |
+LL |     let _ = [1, 2, 3].into_iter(); //~ ERROR equivalent to .iter()
+   |                       ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the Vec
+  --> $DIR/into_iter_on_ref.rs:17:30
+   |
+LL |     let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter()
+   |                              ^^^^^^^^^ help: call directly: `iter`
+   |
+   = note: `-D clippy::into-iter-on-ref` implied by `-D warnings`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the slice
+  --> $DIR/into_iter_on_ref.rs:18:46
+   |
+LL |     let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter()
+   |                                              ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the slice
+  --> $DIR/into_iter_on_ref.rs:19:41
+   |
+LL |     let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+   |                                         ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the slice
+  --> $DIR/into_iter_on_ref.rs:20:44
+   |
+LL |     let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter()
+   |                                            ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the array
+  --> $DIR/into_iter_on_ref.rs:22:32
+   |
+LL |     let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+   |                                ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the array
+  --> $DIR/into_iter_on_ref.rs:23:36
+   |
+LL |     let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter()
+   |                                    ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the array
+  --> $DIR/into_iter_on_ref.rs:24:40
+   |
+LL |     let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut()
+   |                                        ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the Option
+  --> $DIR/into_iter_on_ref.rs:26:24
+   |
+LL |     let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter()
+   |                        ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the Option
+  --> $DIR/into_iter_on_ref.rs:27:28
+   |
+LL |     let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                            ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the Result
+  --> $DIR/into_iter_on_ref.rs:28:32
+   |
+LL |     let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter()
+   |                                ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the Result
+  --> $DIR/into_iter_on_ref.rs:29:37
+   |
+LL |     let _ = (&mut Err::<i32, _>(7)).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                     ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the Vec
+  --> $DIR/into_iter_on_ref.rs:30:34
+   |
+LL |     let _ = (&Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                  ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the Vec
+  --> $DIR/into_iter_on_ref.rs:31:38
+   |
+LL |     let _ = (&mut Vec::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                      ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the BTreeMap
+  --> $DIR/into_iter_on_ref.rs:32:44
+   |
+LL |     let _ = (&BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                            ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the BTreeMap
+  --> $DIR/into_iter_on_ref.rs:33:48
+   |
+LL |     let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                                ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the VecDeque
+  --> $DIR/into_iter_on_ref.rs:34:39
+   |
+LL |     let _ = (&VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                       ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the VecDeque
+  --> $DIR/into_iter_on_ref.rs:35:43
+   |
+LL |     let _ = (&mut VecDeque::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                           ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the LinkedList
+  --> $DIR/into_iter_on_ref.rs:36:41
+   |
+LL |     let _ = (&LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                         ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the LinkedList
+  --> $DIR/into_iter_on_ref.rs:37:45
+   |
+LL |     let _ = (&mut LinkedList::<i32>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                             ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the HashMap
+  --> $DIR/into_iter_on_ref.rs:38:43
+   |
+LL |     let _ = (&HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                           ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter_mut() and will not move the HashMap
+  --> $DIR/into_iter_on_ref.rs:39:47
+   |
+LL |     let _ = (&mut HashMap::<i32, u64>::new()).into_iter(); //~ WARN equivalent to .iter_mut()
+   |                                               ^^^^^^^^^ help: call directly: `iter_mut`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the BTreeSet
+  --> $DIR/into_iter_on_ref.rs:41:39
+   |
+LL |     let _ = (&BTreeSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                       ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the BinaryHeap
+  --> $DIR/into_iter_on_ref.rs:42:41
+   |
+LL |     let _ = (&BinaryHeap::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                         ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the HashSet
+  --> $DIR/into_iter_on_ref.rs:43:38
+   |
+LL |     let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
+   |                                      ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the Path
+  --> $DIR/into_iter_on_ref.rs:44:43
+   |
+LL |     let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
+   |                                           ^^^^^^^^^ help: call directly: `iter`
+
+error: this .into_iter() call is equivalent to .iter() and will not move the PathBuf
+  --> $DIR/into_iter_on_ref.rs:45:47
+   |
+LL |     let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
+   |                                               ^^^^^^^^^ help: call directly: `iter`
+
+error: aborting due to 28 previous errors
+
index ce2596c0c1a4218fa1e49d03beaa9f1fb17db062..4f04c5467d3fbb18ec3df8f2a5a77e041f27e8f3 100644 (file)
@@ -1,6 +1,3 @@
-
-
-
 #![allow(unused)]
 #![feature(core_intrinsics)]
 
@@ -8,8 +5,8 @@
 use std::intrinsics::{init, uninit};
 
 fn main() {
-    let x = 1; 
-    unsafe { 
+    let x = 1;
+    unsafe {
         ref_to_zeroed_std(&x);
         ref_to_zeroed_core(&x);
         ref_to_zeroed_intr(&x);
@@ -24,43 +21,41 @@ fn main() {
 }
 
 unsafe fn ref_to_zeroed_std<T: ?Sized>(t: &T) {
-    let ref_zero: &T = std::mem::zeroed();     // warning
+    let ref_zero: &T = std::mem::zeroed(); // warning
 }
 
 unsafe fn ref_to_zeroed_core<T: ?Sized>(t: &T) {
-    let ref_zero: &T = core::mem::zeroed();   // warning
+    let ref_zero: &T = core::mem::zeroed(); // warning
 }
 
 unsafe fn ref_to_zeroed_intr<T: ?Sized>(t: &T) {
-    let ref_zero: &T = std::intrinsics::init();   // warning
+    let ref_zero: &T = std::intrinsics::init(); // warning
 }
 
 unsafe fn ref_to_uninit_std<T: ?Sized>(t: &T) {
-    let ref_uninit: &T = std::mem::uninitialized();   // warning
+    let ref_uninit: &T = std::mem::uninitialized(); // warning
 }
 
 unsafe fn ref_to_uninit_core<T: ?Sized>(t: &T) {
-    let ref_uninit: &T = core::mem::uninitialized();   // warning
+    let ref_uninit: &T = core::mem::uninitialized(); // warning
 }
 
 unsafe fn ref_to_uninit_intr<T: ?Sized>(t: &T) {
-    let ref_uninit: &T = std::intrinsics::uninit();   // warning
+    let ref_uninit: &T = std::intrinsics::uninit(); // warning
 }
 
 fn some_ref() {
-    let some_ref = &1; 
+    let some_ref = &1;
 }
 
 unsafe fn std_zeroed_no_ref() {
-    let mem_zero: usize = std::mem::zeroed();  // no warning
+    let mem_zero: usize = std::mem::zeroed(); // no warning
 }
 
 unsafe fn core_zeroed_no_ref() {
-    let mem_zero: usize = core::mem::zeroed();  // no warning
+    let mem_zero: usize = core::mem::zeroed(); // no warning
 }
 
 unsafe fn intr_init_no_ref() {
     let mem_zero: usize = std::intrinsics::init(); // no warning
 }
-
-
index f84207385265f56c4afa10574f4f17f851eb473a..9966c347f6e1060eab7bb7036cd4ceeca1808e65 100644 (file)
@@ -1,48 +1,48 @@
 error: reference to zeroed memory
-  --> $DIR/invalid_ref.rs:27:24
+  --> $DIR/invalid_ref.rs:24:24
    |
-27 |     let ref_zero: &T = std::mem::zeroed();     // warning
+LL |     let ref_zero: &T = std::mem::zeroed(); // warning
    |                        ^^^^^^^^^^^^^^^^^^
    |
-   = note: #[deny(invalid_ref)] on by default
+   = note: #[deny(clippy::invalid_ref)] on by default
    = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
 
 error: reference to zeroed memory
-  --> $DIR/invalid_ref.rs:31:24
+  --> $DIR/invalid_ref.rs:28:24
    |
-31 |     let ref_zero: &T = core::mem::zeroed();   // warning
+LL |     let ref_zero: &T = core::mem::zeroed(); // warning
    |                        ^^^^^^^^^^^^^^^^^^^
    |
    = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
 
 error: reference to zeroed memory
-  --> $DIR/invalid_ref.rs:35:24
+  --> $DIR/invalid_ref.rs:32:24
    |
-35 |     let ref_zero: &T = std::intrinsics::init();   // warning
+LL |     let ref_zero: &T = std::intrinsics::init(); // warning
    |                        ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
 
 error: reference to uninitialized memory
-  --> $DIR/invalid_ref.rs:39:26
+  --> $DIR/invalid_ref.rs:36:26
    |
-39 |     let ref_uninit: &T = std::mem::uninitialized();   // warning
+LL |     let ref_uninit: &T = std::mem::uninitialized(); // warning
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
 
 error: reference to uninitialized memory
-  --> $DIR/invalid_ref.rs:43:26
+  --> $DIR/invalid_ref.rs:40:26
    |
-43 |     let ref_uninit: &T = core::mem::uninitialized();   // warning
+LL |     let ref_uninit: &T = core::mem::uninitialized(); // warning
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
 
 error: reference to uninitialized memory
-  --> $DIR/invalid_ref.rs:47:26
+  --> $DIR/invalid_ref.rs:44:26
    |
-47 |     let ref_uninit: &T = std::intrinsics::uninit();   // warning
+LL |     let ref_uninit: &T = std::intrinsics::uninit(); // warning
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
index 5bf0bfdcb98340804960585333f39b6e0904c54e..697416dcee83188c28c87a18489ba261b551c39c 100644 (file)
@@ -1,10 +1,15 @@
+#![warn(clippy::invalid_upcast_comparisons)]
+#![allow(
+    unused,
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::cast_lossless
+)]
 
-
-
-#![warn(invalid_upcast_comparisons)]
-#![allow(unused, eq_op, no_effect, unnecessary_operation, cast_lossless)]
-
-fn mk_value<T>() -> T { unimplemented!() }
+fn mk_value<T>() -> T {
+    unimplemented!()
+}
 
 fn main() {
     let u32: u32 = mk_value();
@@ -45,7 +50,6 @@ fn main() {
     1337 != (u8 as i32);
     1337 != (u8 as u32);
 
-
     // Those are Ok:
     (u8 as u32) > 20;
     42 == (u8 as i32);
index eb46802899e71692ddbac225cd278e9d4dd93fc1..03c3fb80aaabcc1f5adbee634ad8bf256de77b4e 100644 (file)
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:16:5
+  --> $DIR/invalid_upcast_comparisons.rs:21:5
    |
-16 |     (u8 as u32) > 300;
+LL |     (u8 as u32) > 300;
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D invalid-upcast-comparisons` implied by `-D warnings`
+   = note: `-D clippy::invalid-upcast-comparisons` implied by `-D warnings`
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:17:5
+  --> $DIR/invalid_upcast_comparisons.rs:22:5
    |
-17 |     (u8 as i32) > 300;
+LL |     (u8 as i32) > 300;
    |     ^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:18:5
+  --> $DIR/invalid_upcast_comparisons.rs:23:5
    |
-18 |     (u8 as u32) == 300;
+LL |     (u8 as u32) == 300;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:19:5
+  --> $DIR/invalid_upcast_comparisons.rs:24:5
    |
-19 |     (u8 as i32) == 300;
+LL |     (u8 as i32) == 300;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:20:5
+  --> $DIR/invalid_upcast_comparisons.rs:25:5
    |
-20 |     300 < (u8 as u32);
+LL |     300 < (u8 as u32);
    |     ^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:21:5
+  --> $DIR/invalid_upcast_comparisons.rs:26:5
    |
-21 |     300 < (u8 as i32);
+LL |     300 < (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:22:5
+  --> $DIR/invalid_upcast_comparisons.rs:27:5
    |
-22 |     300 == (u8 as u32);
+LL |     300 == (u8 as u32);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:23:5
+  --> $DIR/invalid_upcast_comparisons.rs:28:5
    |
-23 |     300 == (u8 as i32);
+LL |     300 == (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:25:5
+  --> $DIR/invalid_upcast_comparisons.rs:30:5
    |
-25 |     (u8 as u32) <= 300;
+LL |     (u8 as u32) <= 300;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:26:5
+  --> $DIR/invalid_upcast_comparisons.rs:31:5
    |
-26 |     (u8 as i32) <= 300;
+LL |     (u8 as i32) <= 300;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:27:5
+  --> $DIR/invalid_upcast_comparisons.rs:32:5
    |
-27 |     (u8 as u32) != 300;
+LL |     (u8 as u32) != 300;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:28:5
+  --> $DIR/invalid_upcast_comparisons.rs:33:5
    |
-28 |     (u8 as i32) != 300;
+LL |     (u8 as i32) != 300;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:29:5
+  --> $DIR/invalid_upcast_comparisons.rs:34:5
    |
-29 |     300 >= (u8 as u32);
+LL |     300 >= (u8 as u32);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:30:5
+  --> $DIR/invalid_upcast_comparisons.rs:35:5
    |
-30 |     300 >= (u8 as i32);
+LL |     300 >= (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:31:5
+  --> $DIR/invalid_upcast_comparisons.rs:36:5
    |
-31 |     300 != (u8 as u32);
+LL |     300 != (u8 as u32);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:32:5
+  --> $DIR/invalid_upcast_comparisons.rs:37:5
    |
-32 |     300 != (u8 as i32);
+LL |     300 != (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:35:5
+  --> $DIR/invalid_upcast_comparisons.rs:40:5
    |
-35 |     (u8 as i32) < 0;
+LL |     (u8 as i32) < 0;
    |     ^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:36:5
+  --> $DIR/invalid_upcast_comparisons.rs:41:5
    |
-36 |     -5 != (u8 as i32);
+LL |     -5 != (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:38:5
+  --> $DIR/invalid_upcast_comparisons.rs:43:5
    |
-38 |     (u8 as i32) >= 0;
+LL |     (u8 as i32) >= 0;
    |     ^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:39:5
+  --> $DIR/invalid_upcast_comparisons.rs:44:5
    |
-39 |     -5 == (u8 as i32);
+LL |     -5 == (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:42:5
+  --> $DIR/invalid_upcast_comparisons.rs:47:5
    |
-42 |     1337 == (u8 as i32);
+LL |     1337 == (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:43:5
+  --> $DIR/invalid_upcast_comparisons.rs:48:5
    |
-43 |     1337 == (u8 as u32);
+LL |     1337 == (u8 as u32);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:45:5
+  --> $DIR/invalid_upcast_comparisons.rs:50:5
    |
-45 |     1337 != (u8 as i32);
+LL |     1337 != (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:46:5
+  --> $DIR/invalid_upcast_comparisons.rs:51:5
    |
-46 |     1337 != (u8 as u32);
+LL |     1337 != (u8 as u32);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always true
-  --> $DIR/invalid_upcast_comparisons.rs:61:5
+  --> $DIR/invalid_upcast_comparisons.rs:65:5
    |
-61 |     (u8 as i32) > -1;
+LL |     (u8 as i32) > -1;
    |     ^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:62:5
+  --> $DIR/invalid_upcast_comparisons.rs:66:5
    |
-62 |     (u8 as i32) < -1;
+LL |     (u8 as i32) < -1;
    |     ^^^^^^^^^^^^^^^^
 
 error: because of the numeric bounds on `u8` prior to casting, this expression is always false
-  --> $DIR/invalid_upcast_comparisons.rs:78:5
+  --> $DIR/invalid_upcast_comparisons.rs:82:5
    |
-78 |     -5 >= (u8 as i32);
+LL |     -5 >= (u8 as i32);
    |     ^^^^^^^^^^^^^^^^^
 
 error: aborting due to 27 previous errors
diff --git a/tests/ui/issue-3145.rs b/tests/ui/issue-3145.rs
new file mode 100644 (file)
index 0000000..f497d55
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("{}" a); //~ERROR expected token: `,`
+}
diff --git a/tests/ui/issue-3145.stderr b/tests/ui/issue-3145.stderr
new file mode 100644 (file)
index 0000000..f3984f9
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected token: `,`
+  --> $DIR/issue-3145.rs:2:19
+   |
+LL |     println!("{}" a); //~ERROR expected token: `,`
+   |                   ^
+
+error: aborting due to previous error
+
index d4cefb0f1e3ec3640d9675e114fe2e9b9426d400..da580a1839a176b4bf05325302a26c928a16e732 100644 (file)
@@ -1,4 +1,4 @@
-#![deny(while_let_on_iterator)]
+#![deny(clippy::while_let_on_iterator)]
 
 use std::iter::Iterator;
 
index 4b82a0a7565b44a333bd0113e03482e7dafea6cd..d7125901335def0c66b886a02b0e8a6e83464feb 100644 (file)
@@ -1,14 +1,14 @@
 error: this loop could be written as a `for` loop
   --> $DIR/issue_2356.rs:15:29
    |
-15 |         while let Some(e) = it.next() {
+LL |         while let Some(e) = it.next() {
    |                             ^^^^^^^^^ help: try: `for e in it { .. }`
    |
 note: lint level defined here
   --> $DIR/issue_2356.rs:1:9
    |
-1  | #![deny(while_let_on_iterator)]
-   |         ^^^^^^^^^^^^^^^^^^^^^
+LL | #![deny(clippy::while_let_on_iterator)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/tests/ui/issue_3849.rs b/tests/ui/issue_3849.rs
new file mode 100644 (file)
index 0000000..bae4570
--- /dev/null
@@ -0,0 +1,14 @@
+#![allow(dead_code)]
+#![allow(clippy::zero_ptr)]
+#![allow(clippy::transmute_ptr_to_ref)]
+#![allow(clippy::transmuting_null)]
+
+pub const ZPTR: *const usize = 0 as *const _;
+
+fn main() {
+    unsafe {
+        #[clippy::author]
+        let _: &i32 = std::mem::transmute(ZPTR);
+        let _: &i32 = std::mem::transmute(0 as *const i32);
+    }
+}
diff --git a/tests/ui/issue_3849.stdout b/tests/ui/issue_3849.stdout
new file mode 100644 (file)
index 0000000..126c230
--- /dev/null
@@ -0,0 +1,14 @@
+if_chain! {
+    if let StmtKind::Local(ref local) = stmt.node;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Call(ref func, ref args) = init.node;
+    if let ExprKind::Path(ref path) = func.node;
+    if match_qpath(path, &["std", "mem", "transmute"]);
+    if args.len() == 1;
+    if let ExprKind::Path(ref path1) = args[0].node;
+    if match_qpath(path1, &["ZPTR"]);
+    if let PatKind::Wild = local.pat.node;
+    then {
+        // report your lint here
+    }
+}
index 710a1adca565577f9ba464ed6d8b5526bb1a762f..c17a7cbc8d905a7f7484f8491e854404b382188f 100644 (file)
@@ -1,20 +1,24 @@
-
-
-#![warn(items_after_statements)]
+#![warn(clippy::items_after_statements)]
 
 fn ok() {
-    fn foo() { println!("foo"); }
+    fn foo() {
+        println!("foo");
+    }
     foo();
 }
 
 fn last() {
     foo();
-    fn foo() { println!("foo"); }
+    fn foo() {
+        println!("foo");
+    }
 }
 
 fn main() {
     foo();
-    fn foo() { println!("foo"); }
+    fn foo() {
+        println!("foo");
+    }
     foo();
 }
 
@@ -23,7 +27,9 @@ fn mac() {
     println!("{}", a);
     // do not lint this, because it needs to be after `a`
     macro_rules! b {
-        () => {{ a = 6 }}
+        () => {{
+            a = 6
+        }};
     }
     b!();
     println!("{}", a);
index ec1296caf83efbca8fe8a4ce6ea3b1c3cad3dfe9..f8f010b5e5c1fb4c4cdbed207a6f2312f157cb42 100644 (file)
@@ -1,16 +1,20 @@
 error: adding items after statements is confusing, since items exist from the start of the scope
   --> $DIR/item_after_statement.rs:12:5
    |
-12 |     fn foo() { println!("foo"); }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     fn foo() {
+LL | |         println!("foo");
+LL | |     }
+   | |_____^
    |
-   = note: `-D items-after-statements` implied by `-D warnings`
+   = note: `-D clippy::items-after-statements` implied by `-D warnings`
 
 error: adding items after statements is confusing, since items exist from the start of the scope
-  --> $DIR/item_after_statement.rs:17:5
+  --> $DIR/item_after_statement.rs:19:5
    |
-17 |     fn foo() { println!("foo"); }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     fn foo() {
+LL | |         println!("foo");
+LL | |     }
+   | |_____^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs
new file mode 100644 (file)
index 0000000..9c21dd8
--- /dev/null
@@ -0,0 +1,56 @@
+// aux-build:option_helpers.rs
+
+#![warn(clippy::iter_nth)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use option_helpers::IteratorFalsePositives;
+use std::collections::VecDeque;
+
+/// Struct to generate false positives for things with `.iter()`.
+#[derive(Copy, Clone)]
+struct HasIter;
+
+impl HasIter {
+    fn iter(self) -> IteratorFalsePositives {
+        IteratorFalsePositives { foo: 0 }
+    }
+
+    fn iter_mut(self) -> IteratorFalsePositives {
+        IteratorFalsePositives { foo: 0 }
+    }
+}
+
+/// Checks implementation of `ITER_NTH` lint.
+fn iter_nth() {
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
+
+    {
+        // Make sure we lint `.iter()` for relevant types.
+        let bad_vec = some_vec.iter().nth(3);
+        let bad_slice = &some_vec[..].iter().nth(3);
+        let bad_boxed_slice = boxed_slice.iter().nth(3);
+        let bad_vec_deque = some_vec_deque.iter().nth(3);
+    }
+
+    {
+        // Make sure we lint `.iter_mut()` for relevant types.
+        let bad_vec = some_vec.iter_mut().nth(3);
+    }
+    {
+        let bad_slice = &some_vec[..].iter_mut().nth(3);
+    }
+    {
+        let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
+    }
+
+    // Make sure we don't lint for non-relevant types.
+    let false_positive = HasIter;
+    let ok = false_positive.iter().nth(3);
+    let ok_mut = false_positive.iter_mut().nth(3);
+}
+
+fn main() {}
diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr
new file mode 100644 (file)
index 0000000..70412f7
--- /dev/null
@@ -0,0 +1,46 @@
+error: called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable
+  --> $DIR/iter_nth.rs:33:23
+   |
+LL |         let bad_vec = some_vec.iter().nth(3);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-nth` implied by `-D warnings`
+
+error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable
+  --> $DIR/iter_nth.rs:34:26
+   |
+LL |         let bad_slice = &some_vec[..].iter().nth(3);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable
+  --> $DIR/iter_nth.rs:35:31
+   |
+LL |         let bad_boxed_slice = boxed_slice.iter().nth(3);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable
+  --> $DIR/iter_nth.rs:36:29
+   |
+LL |         let bad_vec_deque = some_vec_deque.iter().nth(3);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `.iter_mut().nth()` on a Vec. Calling `.get_mut()` is both faster and more readable
+  --> $DIR/iter_nth.rs:41:23
+   |
+LL |         let bad_vec = some_vec.iter_mut().nth(3);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `.iter_mut().nth()` on a slice. Calling `.get_mut()` is both faster and more readable
+  --> $DIR/iter_nth.rs:44:26
+   |
+LL |         let bad_slice = &some_vec[..].iter_mut().nth(3);
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both faster and more readable
+  --> $DIR/iter_nth.rs:47:29
+   |
+LL |         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs
new file mode 100644 (file)
index 0000000..a65ca3b
--- /dev/null
@@ -0,0 +1,22 @@
+// aux-build:option_helpers.rs
+
+#![warn(clippy::iter_skip_next)]
+#![allow(clippy::blacklisted_name)]
+
+extern crate option_helpers;
+
+use option_helpers::IteratorFalsePositives;
+
+/// Checks implementation of `ITER_SKIP_NEXT` lint
+fn iter_skip_next() {
+    let mut some_vec = vec![0, 1, 2, 3];
+    let _ = some_vec.iter().skip(42).next();
+    let _ = some_vec.iter().cycle().skip(42).next();
+    let _ = (1..10).skip(10).next();
+    let _ = &some_vec[..].iter().skip(3).next();
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.skip(42).next();
+    let _ = foo.filter().skip(42).next();
+}
+
+fn main() {}
diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr
new file mode 100644 (file)
index 0000000..6948bd2
--- /dev/null
@@ -0,0 +1,28 @@
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:13:13
+   |
+LL |     let _ = some_vec.iter().skip(42).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-skip-next` implied by `-D warnings`
+
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:14:13
+   |
+LL |     let _ = some_vec.iter().cycle().skip(42).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:15:13
+   |
+LL |     let _ = (1..10).skip(10).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:16:14
+   |
+LL |     let _ = &some_vec[..].iter().skip(3).next();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/large_digit_groups.fixed b/tests/ui/large_digit_groups.fixed
new file mode 100644 (file)
index 0000000..cf8b36a
--- /dev/null
@@ -0,0 +1,23 @@
+// run-rustfix
+#[warn(clippy::large_digit_groups)]
+#[allow(unused_variables)]
+fn main() {
+    let good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let bad = (
+        0b11_0110_i64,
+        0x0123_4567_8901_usize,
+        123_456_f32,
+        123_456.12_f32,
+        123_456.123_45_f64,
+        123_456.123_456_f64,
+    );
+}
index 5d0fb11dbea56167fdca0736a4b28b99baf37138..5b9aa8c58d8f4c3b6eebaaaf157f5a194f2b8d5a 100644 (file)
@@ -1,8 +1,23 @@
-
-
-#[warn(large_digit_groups)]
+// run-rustfix
+#[warn(clippy::large_digit_groups)]
 #[allow(unused_variables)]
 fn main() {
-    let good = (0b1011_i64, 0o1_234_u32, 0x1_234_567, 1_2345_6789, 1234_f32, 1_234.12_f32, 1_234.123_f32, 1.123_4_f32);
-    let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
+    let good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let bad = (
+        0b1_10110_i64,
+        0x1_23456_78901_usize,
+        1_23456_f32,
+        1_23456.12_f32,
+        1_23456.12345_f64,
+        1_23456.12345_6_f64,
+    );
 }
index f2e6a62d13cceca2b37692c32468b762a3b5a261..4b5d0bd1a9f644138a8b3246e5e94767d893072b 100644 (file)
@@ -1,40 +1,40 @@
 error: digit groups should be smaller
- --> $DIR/large_digit_groups.rs:7:16
-  |
-7 |     let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
-  |                ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
-  |
-  = note: `-D large-digit-groups` implied by `-D warnings`
+  --> $DIR/large_digit_groups.rs:16:9
+   |
+LL |         0b1_10110_i64,
+   |         ^^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
+   |
+   = note: `-D clippy::large-digit-groups` implied by `-D warnings`
 
 error: digit groups should be smaller
- --> $DIR/large_digit_groups.rs:7:31
-  |
-7 |     let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
-  |                               ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
+  --> $DIR/large_digit_groups.rs:17:9
+   |
+LL |         0x1_23456_78901_usize,
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
 
 error: digit groups should be smaller
- --> $DIR/large_digit_groups.rs:7:54
-  |
-7 |     let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
-  |                                                      ^^^^^^^^^^^ help: consider: `123_456_f32`
+  --> $DIR/large_digit_groups.rs:18:9
+   |
+LL |         1_23456_f32,
+   |         ^^^^^^^^^^^ help: consider: `123_456_f32`
 
 error: digit groups should be smaller
- --> $DIR/large_digit_groups.rs:7:67
-  |
-7 |     let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
-  |                                                                   ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32`
+  --> $DIR/large_digit_groups.rs:19:9
+   |
+LL |         1_23456.12_f32,
+   |         ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32`
 
 error: digit groups should be smaller
- --> $DIR/large_digit_groups.rs:7:83
-  |
-7 |     let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
-  |                                                                                   ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f32`
+  --> $DIR/large_digit_groups.rs:20:9
+   |
+LL |         1_23456.12345_f64,
+   |         ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f64`
 
 error: digit groups should be smaller
- --> $DIR/large_digit_groups.rs:7:102
-  |
-7 |     let bad = (0b1_10110_i64, 0x1_23456_78901_usize, 1_23456_f32, 1_23456.12_f32, 1_23456.12345_f32, 1_23456.12345_6_f32);
-  |                                                                                                      ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f32`
+  --> $DIR/large_digit_groups.rs:21:9
+   |
+LL |         1_23456.12345_6_f64,
+   |         ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64`
 
 error: aborting due to 6 previous errors
 
index aaf3e2924b310b71feef6c21afc1fd3ef4a70205..852ef5fec0e7b060332bca56b8fb96e29d555e72 100644 (file)
@@ -1,9 +1,6 @@
-
-
-
 #![allow(dead_code)]
 #![allow(unused_variables)]
-#![warn(large_enum_variant)]
+#![warn(clippy::large_enum_variant)]
 
 enum LargeEnum {
     A(i32),
index 5e938337bc004864d69a0d53284aacfc682e4ef0..b13812612cb848a3242638b2d6bf800d57e75e51 100644 (file)
@@ -1,69 +1,69 @@
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:10:5
+  --> $DIR/large_enum_variant.rs:7:5
    |
-10 |     B([i32; 8000]),
+LL |     B([i32; 8000]),
    |     ^^^^^^^^^^^^^^
    |
-   = note: `-D large-enum-variant` implied by `-D warnings`
+   = note: `-D clippy::large-enum-variant` implied by `-D warnings`
 help: consider boxing the large fields to reduce the total size of the enum
    |
-10 |     B(Box<[i32; 8000]>),
+LL |     B(Box<[i32; 8000]>),
    |       ^^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:21:5
+  --> $DIR/large_enum_variant.rs:18:5
    |
-21 |     C(T, [i32; 8000]),
+LL |     C(T, [i32; 8000]),
    |     ^^^^^^^^^^^^^^^^^
    |
 help: consider boxing the large fields to reduce the total size of the enum
-  --> $DIR/large_enum_variant.rs:21:5
+  --> $DIR/large_enum_variant.rs:18:5
    |
-21 |     C(T, [i32; 8000]),
+LL |     C(T, [i32; 8000]),
    |     ^^^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:34:5
+  --> $DIR/large_enum_variant.rs:31:5
    |
-34 |     ContainingLargeEnum(LargeEnum),
+LL |     ContainingLargeEnum(LargeEnum),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
-34 |     ContainingLargeEnum(Box<LargeEnum>),
+LL |     ContainingLargeEnum(Box<LargeEnum>),
    |                         ^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:37:5
+  --> $DIR/large_enum_variant.rs:34:5
    |
-37 |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+LL |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider boxing the large fields to reduce the total size of the enum
-  --> $DIR/large_enum_variant.rs:37:5
+  --> $DIR/large_enum_variant.rs:34:5
    |
-37 |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+LL |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:44:5
+  --> $DIR/large_enum_variant.rs:41:5
    |
-44 |     StructLikeLarge { x: [i32; 8000], y: i32 },
+LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider boxing the large fields to reduce the total size of the enum
-  --> $DIR/large_enum_variant.rs:44:5
+  --> $DIR/large_enum_variant.rs:41:5
    |
-44 |     StructLikeLarge { x: [i32; 8000], y: i32 },
+LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:49:5
+  --> $DIR/large_enum_variant.rs:46:5
    |
-49 |     StructLikeLarge2 { x: [i32; 8000] },
+LL |     StructLikeLarge2 { x: [i32; 8000] },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
-49 |     StructLikeLarge2 { x: Box<[i32; 8000]> },
+LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
    |                           ^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/len_without_is_empty.rs b/tests/ui/len_without_is_empty.rs
new file mode 100644 (file)
index 0000000..3ef29dd
--- /dev/null
@@ -0,0 +1,145 @@
+#![warn(clippy::len_without_is_empty)]
+#![allow(dead_code, unused)]
+
+pub struct PubOne;
+
+impl PubOne {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+}
+
+impl PubOne {
+    // A second impl for this struct -- the error span shouldn't mention this.
+    pub fn irrelevant(self: &Self) -> bool {
+        false
+    }
+}
+
+// Identical to `PubOne`, but with an `allow` attribute on the impl complaining `len`.
+pub struct PubAllowed;
+
+#[allow(clippy::len_without_is_empty)]
+impl PubAllowed {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+}
+
+// No `allow` attribute on this impl block, but that doesn't matter -- we only require one on the
+// impl containing `len`.
+impl PubAllowed {
+    pub fn irrelevant(self: &Self) -> bool {
+        false
+    }
+}
+
+pub trait PubTraitsToo {
+    fn len(self: &Self) -> isize;
+}
+
+impl PubTraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+pub struct HasIsEmpty;
+
+impl HasIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub struct HasWrongIsEmpty;
+
+impl HasWrongIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    pub fn is_empty(self: &Self, x: u32) -> bool {
+        false
+    }
+}
+
+struct NotPubOne;
+
+impl NotPubOne {
+    pub fn len(self: &Self) -> isize {
+        // No error; `len` is pub but `NotPubOne` is not exported anyway.
+        1
+    }
+}
+
+struct One;
+
+impl One {
+    fn len(self: &Self) -> isize {
+        // No error; `len` is private; see issue #1085.
+        1
+    }
+}
+
+trait TraitsToo {
+    fn len(self: &Self) -> isize;
+    // No error; `len` is private; see issue #1085.
+}
+
+impl TraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+struct HasPrivateIsEmpty;
+
+impl HasPrivateIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+struct Wither;
+
+pub trait WithIsEmpty {
+    fn len(self: &Self) -> isize;
+    fn is_empty(self: &Self) -> bool;
+}
+
+impl WithIsEmpty for Wither {
+    fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub trait Empty {
+    fn is_empty(&self) -> bool;
+}
+
+pub trait InheritingEmpty: Empty {
+    // Must not trigger `LEN_WITHOUT_IS_EMPTY`.
+    fn len(&self) -> isize;
+}
+
+// This used to ICE.
+pub trait Foo: Sized {}
+
+pub trait DependsOnFoo: Foo {
+    fn len(&mut self) -> usize;
+}
+
+fn main() {}
diff --git a/tests/ui/len_without_is_empty.stderr b/tests/ui/len_without_is_empty.stderr
new file mode 100644 (file)
index 0000000..4493b17
--- /dev/null
@@ -0,0 +1,54 @@
+error: item `PubOne` has a public `len` method but no corresponding `is_empty` method
+  --> $DIR/len_without_is_empty.rs:6:1
+   |
+LL | / impl PubOne {
+LL | |     pub fn len(self: &Self) -> isize {
+LL | |         1
+LL | |     }
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::len-without-is-empty` implied by `-D warnings`
+
+error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
+  --> $DIR/len_without_is_empty.rs:37:1
+   |
+LL | / pub trait PubTraitsToo {
+LL | |     fn len(self: &Self) -> isize;
+LL | | }
+   | |_^
+
+error: item `HasIsEmpty` has a public `len` method but a private `is_empty` method
+  --> $DIR/len_without_is_empty.rs:49:1
+   |
+LL | / impl HasIsEmpty {
+LL | |     pub fn len(self: &Self) -> isize {
+LL | |         1
+LL | |     }
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty` method
+  --> $DIR/len_without_is_empty.rs:61:1
+   |
+LL | / impl HasWrongIsEmpty {
+LL | |     pub fn len(self: &Self) -> isize {
+LL | |         1
+LL | |     }
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
+  --> $DIR/len_without_is_empty.rs:141:1
+   |
+LL | / pub trait DependsOnFoo: Foo {
+LL | |     fn len(&mut self) -> usize;
+LL | | }
+   | |_^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed
new file mode 100644 (file)
index 0000000..56109a0
--- /dev/null
@@ -0,0 +1,143 @@
+// run-rustfix
+
+#![warn(clippy::len_zero)]
+#![allow(dead_code, unused, clippy::len_without_is_empty)]
+
+pub struct One;
+struct Wither;
+
+trait TraitsToo {
+    fn len(self: &Self) -> isize;
+    // No error; `len` is private; see issue #1085.
+}
+
+impl TraitsToo for One {
+    fn len(self: &Self) -> isize {
+        0
+    }
+}
+
+pub struct HasIsEmpty;
+
+impl HasIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+pub struct HasWrongIsEmpty;
+
+impl HasWrongIsEmpty {
+    pub fn len(self: &Self) -> isize {
+        1
+    }
+
+    pub fn is_empty(self: &Self, x: u32) -> bool {
+        false
+    }
+}
+
+pub trait WithIsEmpty {
+    fn len(self: &Self) -> isize;
+    fn is_empty(self: &Self) -> bool;
+}
+
+impl WithIsEmpty for Wither {
+    fn len(self: &Self) -> isize {
+        1
+    }
+
+    fn is_empty(self: &Self) -> bool {
+        false
+    }
+}
+
+fn main() {
+    let x = [1, 2];
+    if x.is_empty() {
+        println!("This should not happen!");
+    }
+
+    if "".is_empty() {}
+
+    let y = One;
+    if y.len() == 0 {
+        // No error; `One` does not have `.is_empty()`.
+        println!("This should not happen either!");
+    }
+
+    let z: &TraitsToo = &y;
+    if z.len() > 0 {
+        // No error; `TraitsToo` has no `.is_empty()` method.
+        println!("Nor should this!");
+    }
+
+    let has_is_empty = HasIsEmpty;
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if has_is_empty.len() > 1 {
+        // No error.
+        println!("This can happen.");
+    }
+    if has_is_empty.len() <= 1 {
+        // No error.
+        println!("This can happen.");
+    }
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if !has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if has_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    if 1 < has_is_empty.len() {
+        // No error.
+        println!("This can happen.");
+    }
+    if 1 >= has_is_empty.len() {
+        // No error.
+        println!("This can happen.");
+    }
+    assert!(!has_is_empty.is_empty());
+
+    let with_is_empty: &WithIsEmpty = &Wither;
+    if with_is_empty.is_empty() {
+        println!("Or this!");
+    }
+    assert!(!with_is_empty.is_empty());
+
+    let has_wrong_is_empty = HasWrongIsEmpty;
+    if has_wrong_is_empty.len() == 0 {
+        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
+        println!("Or this!");
+    }
+}
+
+fn test_slice(b: &[u8]) {
+    if !b.is_empty() {}
+}
index 2e71c2761fa09343dd99a9dd5c3d8ec1815880fc..0a77f1194621db3101fd0ed16416749349f6576f 100644 (file)
@@ -1,69 +1,14 @@
-#![warn(len_without_is_empty, len_zero)]
-#![allow(dead_code, unused)]
+// run-rustfix
 
-pub struct PubOne;
+#![warn(clippy::len_zero)]
+#![allow(dead_code, unused, clippy::len_without_is_empty)]
 
-impl PubOne {
-    pub fn len(self: &Self) -> isize {
-        1
-    }
-}
-
-impl PubOne {
-    // A second impl for this struct - the error span shouldn't mention this
-    pub fn irrelevant(self: &Self) -> bool {
-        false
-    }
-}
-
-// Identical to PubOne, but with an allow attribute on the impl complaining len
-pub struct PubAllowed;
-
-#[allow(len_without_is_empty)]
-impl PubAllowed {
-    pub fn len(self: &Self) -> isize {
-        1
-    }
-}
-
-// No allow attribute on this impl block, but that doesn't matter - we only require one on the
-// impl containing len.
-impl PubAllowed {
-    pub fn irrelevant(self: &Self) -> bool {
-        false
-    }
-}
-
-struct NotPubOne;
-
-impl NotPubOne {
-    pub fn len(self: &Self) -> isize {
-        // no error, len is pub but `NotPubOne` is not exported anyway
-        1
-    }
-}
-
-struct One;
-
-impl One {
-    fn len(self: &Self) -> isize {
-        // no error, len is private, see #1085
-        1
-    }
-}
-
-pub trait PubTraitsToo {
-    fn len(self: &Self) -> isize;
-}
-
-impl PubTraitsToo for One {
-    fn len(self: &Self) -> isize {
-        0
-    }
-}
+pub struct One;
+struct Wither;
 
 trait TraitsToo {
-    fn len(self: &Self) -> isize; // no error, len is private, see #1085
+    fn len(self: &Self) -> isize;
+    // No error; `len` is private; see issue #1085.
 }
 
 impl TraitsToo for One {
@@ -72,9 +17,9 @@ fn len(self: &Self) -> isize {
     }
 }
 
-struct HasPrivateIsEmpty;
+pub struct HasIsEmpty;
 
-impl HasPrivateIsEmpty {
+impl HasIsEmpty {
     pub fn len(self: &Self) -> isize {
         1
     }
@@ -84,20 +29,18 @@ fn is_empty(self: &Self) -> bool {
     }
 }
 
-pub struct HasIsEmpty;
+pub struct HasWrongIsEmpty;
 
-impl HasIsEmpty {
+impl HasWrongIsEmpty {
     pub fn len(self: &Self) -> isize {
         1
     }
 
-    fn is_empty(self: &Self) -> bool {
+    pub fn is_empty(self: &Self, x: u32) -> bool {
         false
     }
 }
 
-struct Wither;
-
 pub trait WithIsEmpty {
     fn len(self: &Self) -> isize;
     fn is_empty(self: &Self) -> bool;
@@ -113,27 +56,6 @@ fn is_empty(self: &Self) -> bool {
     }
 }
 
-pub struct HasWrongIsEmpty;
-
-impl HasWrongIsEmpty {
-    pub fn len(self: &Self) -> isize {
-        1
-    }
-
-    pub fn is_empty(self: &Self, x: u32) -> bool {
-        false
-    }
-}
-
-pub trait Empty {
-    fn is_empty(&self) -> bool;
-}
-
-pub trait InheritingEmpty: Empty {
-    //must not trigger LEN_WITHOUT_IS_EMPTY
-    fn len(&self) -> isize;
-}
-
 fn main() {
     let x = [1, 2];
     if x.len() == 0 {
@@ -144,13 +66,13 @@ fn main() {
 
     let y = One;
     if y.len() == 0 {
-        //no error because One does not have .is_empty()
+        // No error; `One` does not have `.is_empty()`.
         println!("This should not happen either!");
     }
 
     let z: &TraitsToo = &y;
     if z.len() > 0 {
-        //no error, because TraitsToo has no .is_empty() method
+        // No error; `TraitsToo` has no `.is_empty()` method.
         println!("Nor should this!");
     }
 
@@ -171,11 +93,11 @@ fn main() {
         println!("Or this!");
     }
     if has_is_empty.len() > 1 {
-        // no error
+        // No error.
         println!("This can happen.");
     }
     if has_is_empty.len() <= 1 {
-        // no error
+        // No error.
         println!("This can happen.");
     }
     if 0 == has_is_empty.len() {
@@ -194,11 +116,11 @@ fn main() {
         println!("Or this!");
     }
     if 1 < has_is_empty.len() {
-        // no error
+        // No error.
         println!("This can happen.");
     }
     if 1 >= has_is_empty.len() {
-        // no error
+        // No error.
         println!("This can happen.");
     }
     assert!(!has_is_empty.is_empty());
@@ -211,7 +133,7 @@ fn main() {
 
     let has_wrong_is_empty = HasWrongIsEmpty;
     if has_wrong_is_empty.len() == 0 {
-        //no error as HasWrongIsEmpty does not have .is_empty()
+        // No error; `HasWrongIsEmpty` does not have `.is_empty()`.
         println!("Or this!");
     }
 }
@@ -219,10 +141,3 @@ fn main() {
 fn test_slice(b: &[u8]) {
     if b.len() != 0 {}
 }
-
-// this used to ICE
-pub trait Foo: Sized {}
-
-pub trait DependsOnFoo: Foo {
-    fn len(&mut self) -> usize;
-}
index a04185bc63fe160252cf32506e36820e33153d3c..9a472b31e215fd4de0f1e4cd0f78dc0be73a0df4 100644 (file)
-error: item `PubOne` has a public `len` method but no corresponding `is_empty` method
-  --> $DIR/len_zero.rs:6:1
-   |
-6  | / impl PubOne {
-7  | |     pub fn len(self: &Self) -> isize {
-8  | |         1
-9  | |     }
-10 | | }
-   | |_^
-   |
-   = note: `-D len-without-is-empty` implied by `-D warnings`
-
-error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
-  --> $DIR/len_zero.rs:55:1
+error: length comparison to zero
+  --> $DIR/len_zero.rs:61:8
    |
-55 | / pub trait PubTraitsToo {
-56 | |     fn len(self: &Self) -> isize;
-57 | | }
-   | |_^
-
-error: item `HasIsEmpty` has a public `len` method but a private `is_empty` method
-  --> $DIR/len_zero.rs:89:1
+LL |     if x.len() == 0 {
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
    |
-89 | / impl HasIsEmpty {
-90 | |     pub fn len(self: &Self) -> isize {
-91 | |         1
-92 | |     }
-...  |
-96 | |     }
-97 | | }
-   | |_^
-
-error: item `HasWrongIsEmpty` has a public `len` method but no corresponding `is_empty` method
-   --> $DIR/len_zero.rs:118:1
-    |
-118 | / impl HasWrongIsEmpty {
-119 | |     pub fn len(self: &Self) -> isize {
-120 | |         1
-121 | |     }
-...   |
-125 | |     }
-126 | | }
-    | |_^
+   = note: `-D clippy::len-zero` implied by `-D warnings`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:139:8
-    |
-139 |     if x.len() == 0 {
-    |        ^^^^^^^^^^^^ help: using `is_empty` is more concise: `x.is_empty()`
-    |
-    = note: `-D len-zero` implied by `-D warnings`
-
-error: length comparison to zero
-   --> $DIR/len_zero.rs:143:8
-    |
-143 |     if "".len() == 0 {}
-    |        ^^^^^^^^^^^^^ help: using `is_empty` is more concise: `"".is_empty()`
+  --> $DIR/len_zero.rs:65:8
+   |
+LL |     if "".len() == 0 {}
+   |        ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:158:8
-    |
-158 |     if has_is_empty.len() == 0 {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:80:8
+   |
+LL |     if has_is_empty.len() == 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:161:8
-    |
-161 |     if has_is_empty.len() != 0 {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:83:8
+   |
+LL |     if has_is_empty.len() != 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:164:8
-    |
-164 |     if has_is_empty.len() > 0 {
-    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:86:8
+   |
+LL |     if has_is_empty.len() > 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-   --> $DIR/len_zero.rs:167:8
-    |
-167 |     if has_is_empty.len() < 1 {
-    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:89:8
+   |
+LL |     if has_is_empty.len() < 1 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-   --> $DIR/len_zero.rs:170:8
-    |
-170 |     if has_is_empty.len() >= 1 {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:92:8
+   |
+LL |     if has_is_empty.len() >= 1 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:181:8
-    |
-181 |     if 0 == has_is_empty.len() {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:103:8
+   |
+LL |     if 0 == has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:184:8
-    |
-184 |     if 0 != has_is_empty.len() {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:106:8
+   |
+LL |     if 0 != has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:187:8
-    |
-187 |     if 0 < has_is_empty.len() {
-    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:109:8
+   |
+LL |     if 0 < has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-   --> $DIR/len_zero.rs:190:8
-    |
-190 |     if 1 <= has_is_empty.len() {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `!has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:112:8
+   |
+LL |     if 1 <= has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-   --> $DIR/len_zero.rs:193:8
-    |
-193 |     if 1 > has_is_empty.len() {
-    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `has_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:115:8
+   |
+LL |     if 1 > has_is_empty.len() {
+   |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:207:8
-    |
-207 |     if with_is_empty.len() == 0 {
-    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is more concise: `with_is_empty.is_empty()`
+  --> $DIR/len_zero.rs:129:8
+   |
+LL |     if with_is_empty.len() == 0 {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-   --> $DIR/len_zero.rs:220:8
-    |
-220 |     if b.len() != 0 {}
-    |        ^^^^^^^^^^^^ help: using `is_empty` is more concise: `!b.is_empty()`
-
-error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
-   --> $DIR/len_zero.rs:226:1
-    |
-226 | / pub trait DependsOnFoo: Foo {
-227 | |     fn len(&mut self) -> usize;
-228 | | }
-    | |_^
+  --> $DIR/len_zero.rs:142:8
+   |
+LL |     if b.len() != 0 {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `!b.is_empty()`
 
-error: aborting due to 19 previous errors
+error: aborting due to 14 previous errors
 
index 564a67d2c8ef0bec81b7d9e53e8124cbd5b17607..802beeb4be6b18360bd5f6e59defababa1319c74 100644 (file)
@@ -1,11 +1,17 @@
-
-
-
-#![allow(unused_variables, unused_assignments, similar_names, blacklisted_name)]
-#![warn(useless_let_if_seq)]
-
-fn f() -> bool { true }
-fn g(x: i32) -> i32 { x + 1 }
+#![allow(
+    unused_variables,
+    unused_assignments,
+    clippy::similar_names,
+    clippy::blacklisted_name
+)]
+#![warn(clippy::useless_let_if_seq)]
+
+fn f() -> bool {
+    true
+}
+fn g(x: i32) -> i32 {
+    x + 1
+}
 
 fn issue985() -> i32 {
     let mut x = 42;
@@ -63,8 +69,7 @@ fn main() {
     if f() {
         f();
         bar = 42;
-    }
-    else {
+    } else {
         f();
     }
 
@@ -103,4 +108,12 @@ fn main() {
     }
 
     baz = 1337;
+
+    // issue 3043 - types with interior mutability should not trigger this lint
+    use std::cell::Cell;
+    let mut val = Cell::new(1);
+    if true {
+        val = Cell::new(2);
+    }
+    println!("{}", val.get());
 }
index b912373f95c67b7af710ede2e4455260f490c543..c53a63a541bc9d9045f62a540620d2df68077606 100644 (file)
@@ -1,50 +1,50 @@
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:57:5
+  --> $DIR/let_if_seq.rs:63:5
    |
-57 | /     let mut foo = 0;
-58 | |     if f() {
-59 | |         foo = 42;
-60 | |     }
+LL | /     let mut foo = 0;
+LL | |     if f() {
+LL | |         foo = 42;
+LL | |     }
    | |_____^ help: it is more idiomatic to write: `let <mut> foo = if f() { 42 } else { 0 };`
    |
-   = note: `-D useless-let-if-seq` implied by `-D warnings`
+   = note: `-D clippy::useless-let-if-seq` implied by `-D warnings`
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:62:5
+  --> $DIR/let_if_seq.rs:68:5
    |
-62 | /     let mut bar = 0;
-63 | |     if f() {
-64 | |         f();
-65 | |         bar = 42;
-...  |
-68 | |         f();
-69 | |     }
+LL | /     let mut bar = 0;
+LL | |     if f() {
+LL | |         f();
+LL | |         bar = 42;
+LL | |     } else {
+LL | |         f();
+LL | |     }
    | |_____^ help: it is more idiomatic to write: `let <mut> bar = if f() { ..; 42 } else { ..; 0 };`
    |
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> $DIR/let_if_seq.rs:71:5
+  --> $DIR/let_if_seq.rs:76:5
    |
-71 | /     let quz;
-72 | |     if f() {
-73 | |         quz = 42;
-74 | |     } else {
-75 | |         quz = 0;
-76 | |     }
+LL | /     let quz;
+LL | |     if f() {
+LL | |         quz = 42;
+LL | |     } else {
+LL | |         quz = 0;
+LL | |     }
    | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
 
 error: `if _ { .. } else { .. }` is an expression
-   --> $DIR/let_if_seq.rs:100:5
-    |
-100 | /     let mut baz = 0;
-101 | |     if f() {
-102 | |         baz = 42;
-103 | |     }
-    | |_____^ help: it is more idiomatic to write: `let <mut> baz = if f() { 42 } else { 0 };`
-    |
-    = note: you might not need `mut` at all
+  --> $DIR/let_if_seq.rs:105:5
+   |
+LL | /     let mut baz = 0;
+LL | |     if f() {
+LL | |         baz = 42;
+LL | |     }
+   | |_____^ help: it is more idiomatic to write: `let <mut> baz = if f() { 42 } else { 0 };`
+   |
+   = note: you might not need `mut` at all
 
 error: aborting due to 4 previous errors
 
index 1083603b2d63b65acb839b533271bf8cf23f49e6..40052f86dd53fe16b62622a8dbe1bdc104db1ab8 100644 (file)
@@ -1,8 +1,5 @@
-
-
 #![allow(unused)]
-
-#![warn(let_and_return)]
+#![warn(clippy::let_and_return)]
 
 fn test() -> i32 {
     let _y = 0; // no warning
@@ -37,10 +34,15 @@ fn test_nowarn_3() -> (i32, i32) {
 }
 
 fn test_nowarn_4() -> i32 {
-    // this should technically warn, but not b/c of let_and_return, but b/c of useless type
+    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
     let x: i32 = 5;
     x
 }
 
-fn main() {
+fn test_nowarn_5(x: i16) -> u16 {
+    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
+    let x = x as u16;
+    x
 }
+
+fn main() {}
index 459b2eafa26f8e1060fd5ac8ced57c2211c718c5..69c4720c9b3fe9839a811b7da8ebc94fe9f5a2cb 100644 (file)
@@ -1,26 +1,26 @@
 error: returning the result of a let binding from a block. Consider returning the expression directly.
-  --> $DIR/let_return.rs:10:5
+  --> $DIR/let_return.rs:7:5
    |
-10 |     x
+LL |     x
    |     ^
    |
-   = note: `-D let-and-return` implied by `-D warnings`
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
 note: this expression can be directly returned
-  --> $DIR/let_return.rs:9:13
+  --> $DIR/let_return.rs:6:13
    |
- |     let x = 5;
+LL |     let x = 5;
    |             ^
 
 error: returning the result of a let binding from a block. Consider returning the expression directly.
-  --> $DIR/let_return.rs:16:9
+  --> $DIR/let_return.rs:13:9
    |
-16 |         x
+LL |         x
    |         ^
    |
 note: this expression can be directly returned
-  --> $DIR/let_return.rs:15:17
+  --> $DIR/let_return.rs:12:17
    |
-15 |         let x = 5;
+LL |         let x = 5;
    |                 ^
 
 error: aborting due to 2 previous errors
index 032dc85f2cd580fc8f4d7811dc77f18b8d8d77d2..dc17c98f6a8a548552e76e9c4e297d59e2159c26 100644 (file)
@@ -1,19 +1,16 @@
-
-
-
-#![warn(let_unit_value)]
+#![warn(clippy::let_unit_value)]
 #![allow(unused_variables)]
 
 macro_rules! let_and_return {
     ($n:expr) => {{
         let ret = $n;
-    }}
+    }};
 }
 
 fn main() {
     let _x = println!("x");
-    let _y = 1;   // this is fine
-    let _z = ((), 1);  // this as well
+    let _y = 1; // this is fine
+    let _z = ((), 1); // this as well
     if true {
         let _a = ();
     }
index da579ec80f315eba317a32ebf597c9ed40e1c574..e1773a402257e30e24d12f045cb64f636c151906 100644 (file)
@@ -1,15 +1,15 @@
 error: this let-binding has unit value. Consider omitting `let _x =`
-  --> $DIR/let_unit.rs:14:5
+  --> $DIR/let_unit.rs:11:5
    |
-14 |     let _x = println!("x");
+LL |     let _x = println!("x");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D let-unit-value` implied by `-D warnings`
+   = note: `-D clippy::let-unit-value` implied by `-D warnings`
 
 error: this let-binding has unit value. Consider omitting `let _a =`
-  --> $DIR/let_unit.rs:18:9
+  --> $DIR/let_unit.rs:15:9
    |
-18 |         let _a = ();
+LL |         let _a = ();
    |         ^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
index 0322d42e81febffaf34b866720f8ba007591c7b9..2cb236fa3bc3843d3303d282d70903e25d8c1859 100644 (file)
@@ -1,59 +1,97 @@
+#![warn(clippy::needless_lifetimes, clippy::extra_unused_lifetimes)]
+#![allow(dead_code, clippy::needless_pass_by_value, clippy::trivially_copy_pass_by_ref)]
 
+fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 
+fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
 
-#![warn(needless_lifetimes, extra_unused_lifetimes)]
-#![allow(dead_code, needless_pass_by_value, trivially_copy_pass_by_ref)]
+// No error; same lifetime on two params.
+fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
 
-fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
+// No error; static involved.
+fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
 
-fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { }
+fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
 
-fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) { } // no error, same lifetime on two params
-
-fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) { } // no error, static involved
-
-fn mut_and_static_input(_x: &mut u8, _y: &'static str) { }
-
-fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x }
+fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
+    x
+}
 
-fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { x } // no error, multiple input refs
+// No error; multiple input refs.
+fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
+    x
+}
 
-fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { x } // no error, multiple input refs
+// No error; multiple input refs.
+fn multiple_in_and_out_2<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
+    x
+}
 
-fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { x } // no error, static involved
+// No error; static involved.
+fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
+    x
+}
 
-fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { Ok(x) } // no error
+// No error.
+fn deep_reference_1<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
+    Ok(x)
+}
 
-fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { x.unwrap() } // no error, two input refs
+// No error; two input refs.
+fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
+    x.unwrap()
+}
 
-fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) }
+fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
+    Ok(x)
+}
 
-// where clause, but without lifetimes
-fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) }
+// Where-clause, but without lifetimes.
+fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
+where
+    T: Copy,
+{
+    Ok(x)
+}
 
 type Ref<'r> = &'r u8;
 
-fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) { } // no error, same lifetime on two params
+// No error; same lifetime on two params.
+fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
 
-fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { }
+fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
 
-fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) { } // no error, bounded lifetime
+// No error; bounded lifetime.
+fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}
 
-fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) where 'b: 'a { } // no error, bounded lifetime
+// No error; bounded lifetime.
+fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
+where
+    'b: 'a,
+{
+}
 
 struct Lt<'a, I: 'static> {
-    x: &'a I
+    x: &'a I,
 }
 
+// No error; fn bound references `'a`.
 fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
-    where F: Fn(Lt<'a, I>) -> Lt<'a, I>  // no error, fn bound references 'a
-{ unreachable!() }
+where
+    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
+{
+    unreachable!()
+}
 
 fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
-    where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>
-{ unreachable!() }
+where
+    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
+{
+    unreachable!()
+}
 
-fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) { // no error, see below
+// No error; see below.
+fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
     f(x);
 }
 
@@ -61,12 +99,17 @@ fn fn_bound_3_cannot_elide() {
     let x = 42;
     let p = &x;
     let mut q = &x;
-    fn_bound_3(p, |y| q = y); // this will fail if we elides lifetimes of `fn_bound_3`
+    // This will fail if we elide lifetimes of `fn_bound_3`.
+    fn_bound_3(p, |y| q = y);
 }
 
-// no error, multiple input refs
+// No error; multiple input refs.
 fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
-    if cond { x } else { f() }
+    if cond {
+        x
+    } else {
+        f()
+    }
 }
 
 struct X {
@@ -74,72 +117,110 @@ struct X {
 }
 
 impl X {
-    fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x }
+    fn self_and_out<'s>(&'s self) -> &'s u8 {
+        &self.x
+    }
 
-    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { &self.x } // no error, multiple input refs
+    // No error; multiple input refs.
+    fn self_and_in_out<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
+        &self.x
+    }
 
-    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { }
+    fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
 
-    fn self_and_same_in<'s>(&'s self, _x: &'s u8) { } // no error, same lifetimes on two params
+    // No error; same lifetimes on two params.
+    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
 }
 
 struct Foo<'a>(&'a u8);
 
 impl<'a> Foo<'a> {
-    fn self_shared_lifetime(&self, _: &'a u8) {} // no error, lifetime 'a not defined in method
-    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {} // no error, bounds exist
+    // No error; lifetime `'a` not defined in method.
+    fn self_shared_lifetime(&self, _: &'a u8) {}
+    // No error; bounds exist.
+    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
 }
 
 fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
     unimplemented!()
 }
 
-fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { unimplemented!() }
+fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
+    unimplemented!()
+}
 
-// no warning, two input lifetimes (named on the reference, anonymous on Foo)
-fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { unimplemented!() }
+// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
+fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
+    unimplemented!()
+}
 
-// no warning, two input lifetimes (anonymous on the reference, named on Foo)
-fn struct_with_lt3<'a>(_foo: &Foo<'a> ) -> &'a str { unimplemented!() }
+// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
+fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
+    unimplemented!()
+}
 
-// no warning, two input lifetimes
-fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b> ) -> &'a str { unimplemented!() }
+// No warning; two input lifetimes.
+fn struct_with_lt4<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
+    unimplemented!()
+}
 
 trait WithLifetime<'a> {}
 
 type WithLifetimeAlias<'a> = WithLifetime<'a>;
 
-// should not warn because it won't build without the lifetime
-fn trait_obj_elided<'a>(_arg: &'a WithLifetime) -> &'a str { unimplemented!() }
+// Should not warn because it won't build without the lifetime.
+fn trait_obj_elided<'a>(_arg: &'a WithLifetime) -> &'a str {
+    unimplemented!()
+}
 
-// this should warn because there is no lifetime on Drop, so this would be
-// unambiguous if we elided the lifetime
-fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() }
+// Should warn because there is no lifetime on `Drop`, so this would be
+// unambiguous if we elided the lifetime.
+fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str {
+    unimplemented!()
+}
 
 type FooAlias<'a> = Foo<'a>;
 
-fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { unimplemented!() }
+fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
+    unimplemented!()
+}
 
-// no warning, two input lifetimes (named on the reference, anonymous on Foo)
-fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { unimplemented!() }
+// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
+fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
+    unimplemented!()
+}
 
-// no warning, two input lifetimes (anonymous on the reference, named on Foo)
-fn alias_with_lt3<'a>(_foo: &FooAlias<'a> ) -> &'a str { unimplemented!() }
+// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
+fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
+    unimplemented!()
+}
 
-// no warning, two input lifetimes
-fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b> ) -> &'a str { unimplemented!() }
+// No warning; two input lifetimes.
+fn alias_with_lt4<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
+    unimplemented!()
+}
 
-fn named_input_elided_output<'a>(_arg: &'a str) -> &str { unimplemented!() }
+fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+    unimplemented!()
+}
 
-fn elided_input_named_output<'a>(_arg: &str) -> &'a str { unimplemented!() }
+fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
+    unimplemented!()
+}
 
-fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() }
-fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) { unimplemented!() }
+fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
+    unimplemented!()
+}
+fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
+    unimplemented!()
+}
 
-// don't warn on these, see #292
-fn trait_bound_bug<'a, T: WithLifetime<'a>>() { unimplemented!() }
+// Don't warn on these; see issue #292.
+fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
+    unimplemented!()
+}
 
-// #740
+// See issue #740.
 struct Test {
     vec: Vec<usize>,
 }
@@ -150,7 +231,6 @@ fn iter<'a>(&'a self) -> Box<Iterator<Item = usize> + 'a> {
     }
 }
 
-
 trait LintContext<'a> {}
 
 fn f<'a, T: LintContext<'a>>(_: &T) {}
@@ -160,5 +240,12 @@ fn test<'a>(x: &'a [u8]) -> u8 {
     *y
 }
 
-fn main() {
+// Issue #3284: give hint regarding lifetime in return type.
+struct Cow<'a> {
+    x: &'a str,
 }
+fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
+    unimplemented!()
+}
+
+fn main() {}
index b69438af9f8207c9faf151d5eb1c70bafa74b222..9eac0407e4d58fd2158af2644a7f86e23a4e3ad3 100644 (file)
-error: explicit lifetimes given in parameter types where they could be elided
- --> $DIR/lifetimes.rs:7:1
-  |
-7 | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) { }
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D needless-lifetimes` implied by `-D warnings`
-
-error: explicit lifetimes given in parameter types where they could be elided
- --> $DIR/lifetimes.rs:9:1
-  |
-9 | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) { }
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:17:1
-   |
-17 | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { x }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:29:1
-   |
-29 | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { Ok(x) }
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:4:1
+   |
+LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:6:1
+   |
+LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:32:1
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:16:1
+   |
+LL | / fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
+LL | |     x
+LL | | }
+   | |_^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:45:1
+   |
+LL | / fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
+LL | |     Ok(x)
+LL | | }
+   | |_^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:50:1
    |
-32 | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> where T: Copy { Ok(x) }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
+LL | | where
+LL | |     T: Copy,
+LL | | {
+LL | |     Ok(x)
+LL | | }
+   | |_^
 
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:38:1
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:62:1
    |
-38 | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:52:1
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:86:1
    |
-52 | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
-53 | |     where for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>
-54 | | { unreachable!() }
-   | |__________________^
+LL | / fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+LL | | where
+LL | |     for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
+LL | | {
+LL | |     unreachable!()
+LL | | }
+   | |_^
 
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:77:5
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:120:5
    |
-77 |     fn self_and_out<'s>(&'s self) -> &'s u8 { &self.x }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     fn self_and_out<'s>(&'s self) -> &'s u8 {
+LL | |         &self.x
+LL | |     }
+   | |_____^
 
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:81:5
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:129:5
    |
-81 |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) { }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: explicit lifetimes given in parameter types where they could be elided
-  --> $DIR/lifetimes.rs:97:1
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:148:1
    |
-97 | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { unimplemented!() }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
+LL | |     unimplemented!()
+LL | | }
+   | |_^
 
-error: explicit lifetimes given in parameter types where they could be elided
-   --> $DIR/lifetimes.rs:117:1
-    |
-117 | fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str { unimplemented!() }
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:178:1
+   |
+LL | / fn trait_obj_elided2<'a>(_arg: &'a Drop) -> &'a str {
+LL | |     unimplemented!()
+LL | | }
+   | |_^
 
-error: explicit lifetimes given in parameter types where they could be elided
-   --> $DIR/lifetimes.rs:121:1
-    |
-121 | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { unimplemented!() }
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:184:1
+   |
+LL | / fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
+LL | |     unimplemented!()
+LL | | }
+   | |_^
 
-error: explicit lifetimes given in parameter types where they could be elided
-   --> $DIR/lifetimes.rs:132:1
-    |
-132 | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { unimplemented!() }
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:203:1
+   |
+LL | / fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+LL | |     unimplemented!()
+LL | | }
+   | |_^
 
-error: explicit lifetimes given in parameter types where they could be elided
-   --> $DIR/lifetimes.rs:136:1
-    |
-136 | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() }
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:211:1
+   |
+LL | / fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
+LL | |     unimplemented!()
+LL | | }
+   | |_^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/lifetimes.rs:247:1
+   |
+LL | / fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
+LL | |     unimplemented!()
+LL | | }
+   | |_^
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/lint_without_lint_pass.rs b/tests/ui/lint_without_lint_pass.rs
new file mode 100644 (file)
index 0000000..81b6398
--- /dev/null
@@ -0,0 +1,39 @@
+#![deny(clippy::internal)]
+#![feature(rustc_private)]
+
+#[macro_use]
+extern crate rustc;
+use rustc::lint::{LintArray, LintPass};
+
+#[macro_use]
+extern crate clippy_lints;
+
+declare_clippy_lint! {
+    pub TEST_LINT,
+    correctness,
+    ""
+}
+
+declare_clippy_lint! {
+    pub TEST_LINT_REGISTERED,
+    correctness,
+    ""
+}
+
+pub struct Pass;
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(TEST_LINT_REGISTERED)
+    }
+
+    fn name(&self) -> &'static str {
+        "TEST_LINT"
+    }
+}
+
+declare_lint_pass!(Pass2 => [TEST_LINT_REGISTERED]);
+
+pub struct Pass3;
+impl_lint_pass!(Pass3 => [TEST_LINT_REGISTERED]);
+
+fn main() {}
diff --git a/tests/ui/lint_without_lint_pass.stderr b/tests/ui/lint_without_lint_pass.stderr
new file mode 100644 (file)
index 0000000..9d0b0d6
--- /dev/null
@@ -0,0 +1,20 @@
+error: the lint `TEST_LINT` is not added to any `LintPass`
+  --> $DIR/lint_without_lint_pass.rs:11:1
+   |
+LL | / declare_clippy_lint! {
+LL | |     pub TEST_LINT,
+LL | |     correctness,
+LL | |     ""
+LL | | }
+   | |_^
+   |
+note: lint level defined here
+  --> $DIR/lint_without_lint_pass.rs:1:9
+   |
+LL | #![deny(clippy::internal)]
+   |         ^^^^^^^^^^^^^^^^
+   = note: #[deny(clippy::lint_without_lint_pass)] implied by #[deny(clippy::internal)]
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
index 581fbbb70c992e9952edd4f5374706787f0071e8..5f3f95bab98057a9d366ed4343afdf27f3e10dea 100644 (file)
@@ -1,6 +1,7 @@
-#![warn(mixed_case_hex_literals)]
-#![warn(unseparated_literal_suffix)]
-#![warn(zero_prefixed_literal)]
+#![warn(clippy::large_digit_groups)]
+#![warn(clippy::mixed_case_hex_literals)]
+#![warn(clippy::unseparated_literal_suffix)]
+#![warn(clippy::zero_prefixed_literal)]
 #![allow(dead_code)]
 
 fn main() {
@@ -36,9 +37,9 @@ fn main() {
     let ok16 = 0xFE_BAFE_ABAB_ABCD;
     let ok17 = 0x123_4567_8901_usize;
 
-    let fail9 = 0xabcdef;
-    let fail10 = 0xBAFEBAFE;
-    let fail11 = 0xabcdeff;
-    let fail12 = 0xabcabcabcabcabcabc;
     let fail13 = 0x1_23456_78901_usize;
+
+    let fail19 = 12_3456_21;
+    let fail22 = 3__4___23;
+    let fail23 = 3__16___23;
 }
index 6f6ea75df10ebf6380b53663174e2192171f0278..22692160d73ad16fc386c5cb955c8e0b864ad003 100644 (file)
 error: inconsistent casing in hexadecimal literal
-  --> $DIR/literals.rs:12:17
+  --> $DIR/literals.rs:13:17
    |
-12 |     let fail1 = 0xabCD;
+LL |     let fail1 = 0xabCD;
    |                 ^^^^^^
    |
-   = note: `-D mixed-case-hex-literals` implied by `-D warnings`
+   = note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
 
 error: inconsistent casing in hexadecimal literal
-  --> $DIR/literals.rs:13:17
+  --> $DIR/literals.rs:14:17
    |
-13 |     let fail2 = 0xabCD_u32;
+LL |     let fail2 = 0xabCD_u32;
    |                 ^^^^^^^^^^
 
 error: inconsistent casing in hexadecimal literal
-  --> $DIR/literals.rs:14:17
+  --> $DIR/literals.rs:15:17
    |
-14 |     let fail2 = 0xabCD_isize;
+LL |     let fail2 = 0xabCD_isize;
    |                 ^^^^^^^^^^^^
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/literals.rs:15:27
+  --> $DIR/literals.rs:16:27
    |
-15 |     let fail_multi_zero = 000_123usize;
+LL |     let fail_multi_zero = 000_123usize;
    |                           ^^^^^^^^^^^^
    |
-   = note: `-D unseparated-literal-suffix` implied by `-D warnings`
+   = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
 
 error: this is a decimal constant
-  --> $DIR/literals.rs:15:27
+  --> $DIR/literals.rs:16:27
    |
-15 |     let fail_multi_zero = 000_123usize;
+LL |     let fail_multi_zero = 000_123usize;
    |                           ^^^^^^^^^^^^
    |
-   = note: `-D zero-prefixed-literal` implied by `-D warnings`
+   = note: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
 help: if you mean to use a decimal constant, remove the `0` to remove confusion
    |
-15 |     let fail_multi_zero = 123usize;
+LL |     let fail_multi_zero = 123usize;
    |                           ^^^^^^^^
 help: if you mean to use an octal constant, use `0o`
    |
-15 |     let fail_multi_zero = 0o123usize;
+LL |     let fail_multi_zero = 0o123usize;
    |                           ^^^^^^^^^^
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/literals.rs:20:17
+  --> $DIR/literals.rs:21:17
    |
-20 |     let fail3 = 1234i32;
+LL |     let fail3 = 1234i32;
    |                 ^^^^^^^
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/literals.rs:21:17
+  --> $DIR/literals.rs:22:17
    |
-21 |     let fail4 = 1234u32;
+LL |     let fail4 = 1234u32;
    |                 ^^^^^^^
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/literals.rs:22:17
+  --> $DIR/literals.rs:23:17
    |
-22 |     let fail5 = 1234isize;
+LL |     let fail5 = 1234isize;
    |                 ^^^^^^^^^
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/literals.rs:23:17
+  --> $DIR/literals.rs:24:17
    |
-23 |     let fail6 = 1234usize;
+LL |     let fail6 = 1234usize;
    |                 ^^^^^^^^^
 
 error: float type suffix should be separated by an underscore
-  --> $DIR/literals.rs:24:17
+  --> $DIR/literals.rs:25:17
    |
-24 |     let fail7 = 1.5f32;
+LL |     let fail7 = 1.5f32;
    |                 ^^^^^^
 
 error: this is a decimal constant
-  --> $DIR/literals.rs:28:17
+  --> $DIR/literals.rs:29:17
    |
-28 |     let fail8 = 0123;
+LL |     let fail8 = 0123;
    |                 ^^^^
 help: if you mean to use a decimal constant, remove the `0` to remove confusion
    |
-28 |     let fail8 = 123;
+LL |     let fail8 = 123;
    |                 ^^^
 help: if you mean to use an octal constant, use `0o`
    |
-28 |     let fail8 = 0o123;
+LL |     let fail8 = 0o123;
    |                 ^^^^^
 
-error: long literal lacking separators
-  --> $DIR/literals.rs:39:17
-   |
-39 |     let fail9 = 0xabcdef;
-   |                 ^^^^^^^^ help: consider: `0x00ab_cdef`
-   |
-   = note: `-D unreadable-literal` implied by `-D warnings`
-
-error: long literal lacking separators
+error: digit groups should be smaller
   --> $DIR/literals.rs:40:18
    |
-40 |     let fail10 = 0xBAFEBAFE;
-   |                  ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
-
-error: long literal lacking separators
-  --> $DIR/literals.rs:41:18
+LL |     let fail13 = 0x1_23456_78901_usize;
+   |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
    |
-41 |     let fail11 = 0xabcdeff;
-   |                  ^^^^^^^^^ help: consider: `0x0abc_deff`
+   = note: `-D clippy::large-digit-groups` implied by `-D warnings`
 
-error: long literal lacking separators
+error: digits grouped inconsistently by underscores
   --> $DIR/literals.rs:42:18
    |
-42 |     let fail12 = 0xabcabcabcabcabcabc;
-   |                  ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
+LL |     let fail19 = 12_3456_21;
+   |                  ^^^^^^^^^^ help: consider: `12_345_621`
+   |
+   = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
 
-error: digit groups should be smaller
+error: digits grouped inconsistently by underscores
   --> $DIR/literals.rs:43:18
    |
-43 |     let fail13 = 0x1_23456_78901_usize;
-   |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
+LL |     let fail22 = 3__4___23;
+   |                  ^^^^^^^^^ help: consider: `3_423`
+
+error: digits grouped inconsistently by underscores
+  --> $DIR/literals.rs:44:18
    |
-   = note: `-D large-digit-groups` implied by `-D warnings`
+LL |     let fail23 = 3__16___23;
+   |                  ^^^^^^^^^^ help: consider: `31_623`
 
-error: aborting due to 16 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs
new file mode 100644 (file)
index 0000000..aa34728
--- /dev/null
@@ -0,0 +1,110 @@
+#![warn(clippy::needless_range_loop, clippy::manual_memcpy)]
+
+const LOOP_OFFSET: usize = 5000;
+
+pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
+    // plain manual memcpy
+    for i in 0..src.len() {
+        dst[i] = src[i];
+    }
+
+    // dst offset memcpy
+    for i in 0..src.len() {
+        dst[i + 10] = src[i];
+    }
+
+    // src offset memcpy
+    for i in 0..src.len() {
+        dst[i] = src[i + 10];
+    }
+
+    // src offset memcpy
+    for i in 11..src.len() {
+        dst[i] = src[i - 10];
+    }
+
+    // overwrite entire dst
+    for i in 0..dst.len() {
+        dst[i] = src[i];
+    }
+
+    // manual copy with branch - can't easily convert to memcpy!
+    for i in 0..src.len() {
+        dst[i] = src[i];
+        if dst[i] > 5 {
+            break;
+        }
+    }
+
+    // multiple copies - suggest two memcpy statements
+    for i in 10..256 {
+        dst[i] = src[i - 5];
+        dst2[i + 500] = src[i]
+    }
+
+    // this is a reversal - the copy lint shouldn't be triggered
+    for i in 10..LOOP_OFFSET {
+        dst[i + LOOP_OFFSET] = src[LOOP_OFFSET - i];
+    }
+
+    let some_var = 5;
+    // Offset in variable
+    for i in 10..LOOP_OFFSET {
+        dst[i + LOOP_OFFSET] = src[i - some_var];
+    }
+
+    // Non continuous copy - don't trigger lint
+    for i in 0..10 {
+        dst[i + i] = src[i];
+    }
+
+    let src_vec = vec![1, 2, 3, 4, 5];
+    let mut dst_vec = vec![0, 0, 0, 0, 0];
+
+    // make sure vectors are supported
+    for i in 0..src_vec.len() {
+        dst_vec[i] = src_vec[i];
+    }
+
+    // lint should not trigger when either
+    // source or destination type is not
+    // slice-like, like DummyStruct
+    struct DummyStruct(i32);
+
+    impl ::std::ops::Index<usize> for DummyStruct {
+        type Output = i32;
+
+        fn index(&self, _: usize) -> &i32 {
+            &self.0
+        }
+    }
+
+    let src = DummyStruct(5);
+    let mut dst_vec = vec![0; 10];
+
+    for i in 0..10 {
+        dst_vec[i] = src[i];
+    }
+
+    // Simplify suggestion (issue #3004)
+    let src = [0, 1, 2, 3, 4];
+    let mut dst = [0, 0, 0, 0, 0, 0];
+    let from = 1;
+
+    for i in from..from + src.len() {
+        dst[i] = src[i - from];
+    }
+
+    for i in from..from + 3 {
+        dst[i] = src[i - from];
+    }
+}
+
+#[warn(clippy::needless_range_loop, clippy::manual_memcpy)]
+pub fn manual_clone(src: &[String], dst: &mut [String]) {
+    for i in 0..src.len() {
+        dst[i] = src[i].clone();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr
new file mode 100644 (file)
index 0000000..49ab83f
--- /dev/null
@@ -0,0 +1,75 @@
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:7:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
+   |
+   = note: `-D clippy::manual-memcpy` implied by `-D warnings`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:12:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:17:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:22:14
+   |
+LL |     for i in 11..src.len() {
+   |              ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:27:14
+   |
+LL |     for i in 0..dst.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:40:14
+   |
+LL |     for i in 10..256 {
+   |              ^^^^^^^
+help: try replacing the loop by
+   |
+LL |     for i in dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)])
+LL |     dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) {
+   |
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:52:14
+   |
+LL |     for i in 10..LOOP_OFFSET {
+   |              ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:65:14
+   |
+LL |     for i in 0..src_vec.len() {
+   |              ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:94:14
+   |
+LL |     for i in from..from + src.len() {
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:98:14
+   |
+LL |     for i in from..from + 3 {
+   |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:105:14
+   |
+LL |     for i in 0..src.len() {
+   |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/many_single_char_names.rs b/tests/ui/many_single_char_names.rs
new file mode 100644 (file)
index 0000000..81c0427
--- /dev/null
@@ -0,0 +1,73 @@
+#[warn(clippy::many_single_char_names)]
+
+fn bla() {
+    let a: i32;
+    let (b, c, d): (i32, i64, i16);
+    {
+        {
+            let cdefg: i32;
+            let blar: i32;
+        }
+        {
+            let e: i32;
+        }
+        {
+            let e: i32;
+            let f: i32;
+        }
+        match 5 {
+            1 => println!(),
+            e => panic!(),
+        }
+        match 5 {
+            1 => println!(),
+            _ => panic!(),
+        }
+    }
+}
+
+fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
+
+fn bindings2() {
+    let (a, b, c, d, e, f, g, h) = unimplemented!();
+}
+
+fn shadowing() {
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    let a = 0i32;
+    {
+        let a = 0i32;
+    }
+}
+
+fn patterns() {
+    enum Z {
+        A(i32),
+        B(i32),
+        C(i32),
+        D(i32),
+        E(i32),
+        F(i32),
+    }
+
+    // These should not trigger a warning, since the pattern bindings are a new scope.
+    match Z::A(0) {
+        Z::A(a) => {},
+        Z::B(b) => {},
+        Z::C(c) => {},
+        Z::D(d) => {},
+        Z::E(e) => {},
+        Z::F(f) => {},
+    }
+}
+
+#[allow(clippy::many_single_char_names)]
+fn issue_3198_allow_works() {
+    let (a, b, c, d, e) = (0, 0, 0, 0, 0);
+}
+
+fn main() {}
diff --git a/tests/ui/many_single_char_names.stderr b/tests/ui/many_single_char_names.stderr
new file mode 100644 (file)
index 0000000..a746667
--- /dev/null
@@ -0,0 +1,51 @@
+error: 5 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:4:9
+   |
+LL |     let a: i32;
+   |         ^
+LL |     let (b, c, d): (i32, i64, i16);
+   |          ^  ^  ^
+...
+LL |             let e: i32;
+   |                 ^
+   |
+   = note: `-D clippy::many-single-char-names` implied by `-D warnings`
+
+error: 6 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:4:9
+   |
+LL |     let a: i32;
+   |         ^
+LL |     let (b, c, d): (i32, i64, i16);
+   |          ^  ^  ^
+...
+LL |             let e: i32;
+   |                 ^
+LL |             let f: i32;
+   |                 ^
+
+error: 5 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:4:9
+   |
+LL |     let a: i32;
+   |         ^
+LL |     let (b, c, d): (i32, i64, i16);
+   |          ^  ^  ^
+...
+LL |             e => panic!(),
+   |             ^
+
+error: 8 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:29:13
+   |
+LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
+   |             ^       ^       ^       ^       ^       ^       ^       ^
+
+error: 8 bindings with single-character names in scope
+  --> $DIR/many_single_char_names.rs:32:10
+   |
+LL |     let (a, b, c, d, e, f, g, h) = unimplemented!();
+   |          ^  ^  ^  ^  ^  ^  ^  ^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed
new file mode 100644 (file)
index 0000000..c8b9bc0
--- /dev/null
@@ -0,0 +1,26 @@
+// run-rustfix
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::iter_cloned_collect)]
+#![allow(clippy::clone_on_copy)]
+#![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::redundant_closure_for_method_calls)]
+
+fn main() {
+    let _: Vec<i8> = vec![5_i8; 6].iter().copied().collect();
+    let _: Vec<String> = vec![String::new()].iter().cloned().collect();
+    let _: Vec<u32> = vec![42, 43].iter().copied().collect();
+    let _: Option<u64> = Some(Box::new(16)).map(|b| *b);
+    let _: Option<u64> = Some(&16).copied();
+    let _: Option<u8> = Some(&1).copied();
+
+    // Don't lint these
+    let v = vec![5_i8; 6];
+    let a = 0;
+    let b = &a;
+    let _ = v.iter().map(|_x| *b);
+    let _ = v.iter().map(|_x| a.clone());
+    let _ = v.iter().map(|&_x| a);
+
+    // Issue #498
+    let _ = std::env::args();
+}
index f11d21d2dfafdada06da7379306e610fe46cad0b..5f216823eb4a959066f5a85fb298677844a2ab96 100644 (file)
-
-
-
-#![warn(map_clone)]
-
-#![allow(clone_on_copy, unused)]
-
-use std::ops::Deref;
-
-fn map_clone_iter() {
-    let x = [1,2,3];
-    x.iter().map(|y| y.clone());
-
-    x.iter().map(|&y| y);
-
-    x.iter().map(|y| *y);
-
-    x.iter().map(|y| { y.clone() });
-
-    x.iter().map(|&y| { y });
-
-    x.iter().map(|y| { *y });
-
-    x.iter().map(Clone::clone);
-
-}
-
-fn map_clone_option() {
-    let x = Some(4);
-    x.as_ref().map(|y| y.clone());
-
-    x.as_ref().map(|&y| y);
-
-    x.as_ref().map(|y| *y);
-
+// run-rustfix
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::iter_cloned_collect)]
+#![allow(clippy::clone_on_copy)]
+#![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::redundant_closure_for_method_calls)]
+
+fn main() {
+    let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
+    let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
+    let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
+    let _: Option<u64> = Some(Box::new(16)).map(|b| *b);
+    let _: Option<u64> = Some(&16).map(|b| *b);
+    let _: Option<u8> = Some(&1).map(|x| x.clone());
+
+    // Don't lint these
+    let v = vec![5_i8; 6];
+    let a = 0;
+    let b = &a;
+    let _ = v.iter().map(|_x| *b);
+    let _ = v.iter().map(|_x| a.clone());
+    let _ = v.iter().map(|&_x| a);
+
+    // Issue #498
+    let _ = std::env::args().map(|v| v.clone());
 }
-
-fn not_linted_option() {
-    let x = Some(5);
-
-    // Not linted: other statements
-    x.as_ref().map(|y| {
-        println!("y: {}", y);
-        y.clone()
-    });
-
-    // Not linted: argument bindings
-    let x = Some((6, 7));
-    x.map(|(y, _)| y.clone());
-
-    // Not linted: cloning something else
-    x.map(|y| y.0.clone());
-
-    // Not linted: no dereferences
-    x.map(|y| y);
-
-    // Not linted: multiple dereferences
-    let _: Option<(i32, i32)> = x.as_ref().as_ref().map(|&&x| x);
-}
-
-#[derive(Copy, Clone)]
-struct Wrapper<T>(T);
-impl<T> Wrapper<T> {
-    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Wrapper<U> {
-        Wrapper(f(self.0))
-    }
-}
-
-fn map_clone_other() {
-    let eight = 8;
-    let x = Wrapper(&eight);
-
-    // Not linted: not a linted type
-    x.map(|y| y.clone());
-    x.map(|&y| y);
-    x.map(|y| *y);
-}
-
-#[derive(Copy, Clone)]
-struct UnusualDeref;
-static NINE: i32 = 9;
-
-impl Deref for UnusualDeref {
-    type Target = i32;
-    fn deref(&self) -> &i32 { &NINE }
-}
-
-fn map_clone_deref() {
-    let x = Some(UnusualDeref);
-    let _: Option<UnusualDeref> = x.as_ref().map(|y| *y);
-
-
-    // Not linted: using deref conversion
-    let _: Option<i32> = x.map(|y| *y);
-
-    // Not linted: using regular deref but also deref conversion
-    let _: Option<i32> = x.as_ref().map(|y| **y);
-}
-
-// stuff that used to be a false positive
-fn former_false_positive() {
-    vec![1].iter_mut().map(|x| *x); // #443
-}
-
-fn main() { }
index c29f37918517634cf66b958b42dbe7997ec906a5..35e234a73296e3438ab618c01f7ea94b49039839 100644 (file)
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:12:5
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:9:22
    |
-12 |     x.iter().map(|y| y.clone());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
    |
-   = note: `-D map-clone` implied by `-D warnings`
-   = help: try
-           x.iter().cloned()
+   = note: `-D clippy::map-clone` implied by `-D warnings`
 
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:14:5
+error: You are using an explicit closure for cloning elements
+  --> $DIR/map_clone.rs:10:26
    |
-14 |     x.iter().map(|&y| y);
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.iter().cloned()
-
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:16:5
-   |
-16 |     x.iter().map(|y| *y);
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.iter().cloned()
-
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:18:5
-   |
-18 |     x.iter().map(|y| { y.clone() });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.iter().cloned()
-
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:20:5
-   |
-20 |     x.iter().map(|&y| { y });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.iter().cloned()
+LL |     let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
 
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:22:5
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:11:23
    |
-22 |     x.iter().map(|y| { *y });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.iter().cloned()
-
-error: you seem to be using .map() to clone the contents of an iterator, consider using `.cloned()`
-  --> $DIR/map_clone.rs:24:5
-   |
-24 |     x.iter().map(Clone::clone);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.iter().cloned()
-
-error: you seem to be using .map() to clone the contents of an Option, consider using `.cloned()`
-  --> $DIR/map_clone.rs:30:5
-   |
-30 |     x.as_ref().map(|y| y.clone());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.as_ref().cloned()
+LL |     let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
 
-error: you seem to be using .map() to clone the contents of an Option, consider using `.cloned()`
-  --> $DIR/map_clone.rs:32:5
-   |
-32 |     x.as_ref().map(|&y| y);
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:13:26
    |
-   = help: try
-           x.as_ref().cloned()
+LL |     let _: Option<u64> = Some(&16).map(|b| *b);
+   |                          ^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&16).copied()`
 
-error: you seem to be using .map() to clone the contents of an Option, consider using `.cloned()`
-  --> $DIR/map_clone.rs:34:5
+error: You are using an explicit closure for copying elements
+  --> $DIR/map_clone.rs:14:25
    |
-34 |     x.as_ref().map(|y| *y);
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try
-           x.as_ref().cloned()
+LL |     let _: Option<u8> = Some(&1).map(|x| x.clone());
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider calling the dedicated `copied` method: `Some(&1).copied()`
 
-error: you seem to be using .map() to clone the contents of an Option, consider using `.cloned()`
-  --> $DIR/map_clone.rs:90:35
-   |
-90 |     let _: Option<UnusualDeref> = x.as_ref().map(|y| *y);
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^
+error: You are needlessly cloning iterator elements
+  --> $DIR/map_clone.rs:25:29
    |
-   = help: try
-           x.as_ref().cloned()
+LL |     let _ = std::env::args().map(|v| v.clone());
+   |                             ^^^^^^^^^^^^^^^^^^^ help: Remove the map call
 
-error: aborting due to 11 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs
new file mode 100644 (file)
index 0000000..d0720c4
--- /dev/null
@@ -0,0 +1,6 @@
+#![warn(clippy::all, clippy::pedantic)]
+#![allow(clippy::missing_docs_in_private_items)]
+
+fn main() {
+    let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
+}
diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr
new file mode 100644 (file)
index 0000000..822d273
--- /dev/null
@@ -0,0 +1,10 @@
+error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)`
+  --> $DIR/map_flatten.rs:5:21
+   |
+LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using flat_map instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)`
+   |
+   = note: `-D clippy::map-flatten` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/map_unit_fn.rs b/tests/ui/map_unit_fn.rs
new file mode 100644 (file)
index 0000000..9a74da4
--- /dev/null
@@ -0,0 +1,11 @@
+#![allow(unused)]
+struct Mappable {}
+
+impl Mappable {
+    pub fn map(&self) {}
+}
+
+fn main() {
+    let m = Mappable {};
+    m.map();
+}
diff --git a/tests/ui/map_unit_fn.stderr b/tests/ui/map_unit_fn.stderr
deleted file mode 100644 (file)
index c4ee0ce..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:33:5
-   |
-33 |     x.field.map(do_nothing);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(x_field) = x.field { do_nothing(...) }`
-   |
-   = note: `-D option-map-unit-fn` implied by `-D warnings`
-
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:35:5
-   |
-35 |     x.field.map(do_nothing);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(x_field) = x.field { do_nothing(...) }`
-
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:37:5
-   |
-37 |     x.field.map(diverge);
-   |     ^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(x_field) = x.field { diverge(...) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:43:5
-   |
-43 |     x.field.map(|value| x.do_option_nothing(value + captured));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:45:5
-   |
-45 |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:48:5
-   |
-48 |     x.field.map(|value| do_nothing(value + captured));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:50:5
-   |
-50 |     x.field.map(|value| { do_nothing(value + captured) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:52:5
-   |
-52 |     x.field.map(|value| { do_nothing(value + captured); });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:54:5
-   |
-54 |     x.field.map(|value| { { do_nothing(value + captured); } });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:57:5
-   |
-57 |     x.field.map(|value| diverge(value + captured));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:59:5
-   |
-59 |     x.field.map(|value| { diverge(value + captured) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:61:5
-   |
-61 |     x.field.map(|value| { diverge(value + captured); });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:63:5
-   |
-63 |     x.field.map(|value| { { diverge(value + captured); } });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:68:5
-   |
-68 |     x.field.map(|value| { let y = plus_one(value + captured); });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:70:5
-   |
-70 |     x.field.map(|value| { plus_one(value + captured); });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:72:5
-   |
-72 |     x.field.map(|value| { { plus_one(value + captured); } });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:75:5
-   |
-75 |     x.field.map(|ref value| { do_nothing(value + captured) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:78:5
-   |
-78 |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { ... }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:80:5
-   |
-80 |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { ... }`
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:84:5
-   |
-84 |        x.field.map(|value| {
-   |   _____^
-   |  |_____|
-   | ||
-85 | ||         do_nothing(value);
-86 | ||         do_nothing(value)
-87 | ||     });
-   | ||______^- help: try this: `if let Some(value) = x.field { ... }`
-   | |_______|
-   | 
-
-error: called `map(f)` on an Option value where `f` is a unit closure
-  --> $DIR/map_unit_fn.rs:88:5
-   |
-88 |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(value) = x.field { ... }`
-
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:91:5
-   |
-91 |     Some(42).map(diverge);
-   |     ^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(_) = Some(42) { diverge(...) }`
-
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:92:5
-   |
-92 |     "12".parse::<i32>().ok().map(diverge);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(_) = "12".parse::<i32>().ok() { diverge(...) }`
-
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:93:5
-   |
-93 |     Some(plus_one(1)).map(do_nothing);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(_) = Some(plus_one(1)) { do_nothing(...) }`
-
-error: called `map(f)` on an Option value where `f` is a unit function
-  --> $DIR/map_unit_fn.rs:97:5
-   |
-97 |     y.map(do_nothing);
-   |     ^^^^^^^^^^^^^^^^^-
-   |     |
-   |     help: try this: `if let Some(_y) = y { do_nothing(...) }`
-
-error: aborting due to 25 previous errors
-
diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed
new file mode 100644 (file)
index 0000000..7508536
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::match_as_ref)]
+
+fn match_as_ref() {
+    let owned: Option<()> = None;
+    let borrowed: Option<&()> = owned.as_ref();
+
+    let mut mut_owned: Option<()> = None;
+    let borrow_mut: Option<&mut ()> = mut_owned.as_mut();
+}
+
+fn main() {}
diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs
new file mode 100644 (file)
index 0000000..62c06f3
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::match_as_ref)]
+
+fn match_as_ref() {
+    let owned: Option<()> = None;
+    let borrowed: Option<&()> = match owned {
+        None => None,
+        Some(ref v) => Some(v),
+    };
+
+    let mut mut_owned: Option<()> = None;
+    let borrow_mut: Option<&mut ()> = match mut_owned {
+        None => None,
+        Some(ref mut v) => Some(v),
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr
new file mode 100644 (file)
index 0000000..09115b8
--- /dev/null
@@ -0,0 +1,24 @@
+error: use as_ref() instead
+  --> $DIR/match_as_ref.rs:8:33
+   |
+LL |       let borrowed: Option<&()> = match owned {
+   |  _________________________________^
+LL | |         None => None,
+LL | |         Some(ref v) => Some(v),
+LL | |     };
+   | |_____^ help: try this: `owned.as_ref()`
+   |
+   = note: `-D clippy::match-as-ref` implied by `-D warnings`
+
+error: use as_mut() instead
+  --> $DIR/match_as_ref.rs:14:39
+   |
+LL |       let borrow_mut: Option<&mut ()> = match mut_owned {
+   |  _______________________________________^
+LL | |         None => None,
+LL | |         Some(ref mut v) => Some(v),
+LL | |     };
+   | |_____^ help: try this: `mut_owned.as_mut()`
+
+error: aborting due to 2 previous errors
+
index 07efe2c68084e1b033fb40eff465a13223eae090..a7af8ce01083e582046868f30716e399f7ae193e 100644 (file)
@@ -14,31 +14,40 @@ fn match_bool() {
 
     match test {
         true => (),
-        false => { println!("Noooo!"); }
+        false => {
+            println!("Noooo!");
+        },
     };
 
     match test {
-        false => { println!("Noooo!"); }
+        false => {
+            println!("Noooo!");
+        },
         _ => (),
     };
 
     match test && test {
-        false => { println!("Noooo!"); }
+        false => {
+            println!("Noooo!");
+        },
         _ => (),
     };
 
     match test {
-        false => { println!("Noooo!"); }
-        true => { println!("Yes!"); }
+        false => {
+            println!("Noooo!");
+        },
+        true => {
+            println!("Yes!");
+        },
     };
 
     // Not linted
     match option {
-        1 ... 10 => 1,
-        11 ... 20 => 2,
+        1...10 => 1,
+        11...20 => 2,
         _ => 3,
     };
 }
 
-fn main() {
-}
+fn main() {}
index 89378f438b0249af78d93c939730efa85c655f93..193e6c17238bd31505cf934ece2c9edf261d12b2 100644 (file)
 error: this boolean expression can be simplified
-  --> $DIR/match_bool.rs:25:11
+  --> $DIR/match_bool.rs:29:11
    |
-25 |     match test && test {
+LL |     match test && test {
    |           ^^^^^^^^^^^^ help: try: `test`
    |
-   = note: `-D nonminimal-bool` implied by `-D warnings`
+   = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
 
 error: you seem to be trying to match on a boolean expression
- --> $DIR/match_bool.rs:4:5
-  |
-4 | /     match test {
-5 | |         true => 0,
-6 | |         false => 42,
-7 | |     };
-  | |_____^ help: consider using an if/else expression: `if test { 0 } else { 42 }`
-  |
-  = note: `-D match-bool` implied by `-D warnings`
 --> $DIR/match_bool.rs:4:5
+   |
+LL | /     match test {
+LL | |         true => 0,
+LL | |         false => 42,
+LL | |     };
+   | |_____^ help: consider using an if/else expression: `if test { 0 } else { 42 }`
+   |
+   = note: `-D clippy::match-bool` implied by `-D warnings`
 
 error: you seem to be trying to match on a boolean expression
   --> $DIR/match_bool.rs:10:5
    |
-10 | /     match option == 1 {
-11 | |         true => 1,
-12 | |         false => 0,
-13 | |     };
+LL | /     match option == 1 {
+LL | |         true => 1,
+LL | |         false => 0,
+LL | |     };
    | |_____^ help: consider using an if/else expression: `if option == 1 { 1 } else { 0 }`
 
 error: you seem to be trying to match on a boolean expression
   --> $DIR/match_bool.rs:15:5
    |
-15 | /     match test {
-16 | |         true => (),
-17 | |         false => { println!("Noooo!"); }
-18 | |     };
-   | |_____^ help: consider using an if/else expression: `if !test { println!("Noooo!"); }`
+LL | /     match test {
+LL | |         true => (),
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+LL | |     };
+   | |_____^
+help: consider using an if/else expression
+   |
+LL |     if !test {
+LL |     println!("Noooo!");
+LL | };
+   |
 
 error: you seem to be trying to match on a boolean expression
-  --> $DIR/match_bool.rs:20:5
+  --> $DIR/match_bool.rs:22:5
+   |
+LL | /     match test {
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+LL | |         _ => (),
+LL | |     };
+   | |_____^
+help: consider using an if/else expression
+   |
+LL |     if !test {
+LL |     println!("Noooo!");
+LL | };
    |
-20 | /     match test {
-21 | |         false => { println!("Noooo!"); }
-22 | |         _ => (),
-23 | |     };
-   | |_____^ help: consider using an if/else expression: `if !test { println!("Noooo!"); }`
 
 error: you seem to be trying to match on a boolean expression
-  --> $DIR/match_bool.rs:25:5
+  --> $DIR/match_bool.rs:29:5
+   |
+LL | /     match test && test {
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+LL | |         _ => (),
+LL | |     };
+   | |_____^
+help: consider using an if/else expression
+   |
+LL |     if !(test && test) {
+LL |     println!("Noooo!");
+LL | };
    |
-25 | /     match test && test {
-26 | |         false => { println!("Noooo!"); }
-27 | |         _ => (),
-28 | |     };
-   | |_____^ help: consider using an if/else expression: `if !(test && test) { println!("Noooo!"); }`
 
 error: equal expressions as operands to `&&`
-  --> $DIR/match_bool.rs:25:11
+  --> $DIR/match_bool.rs:29:11
    |
-25 |     match test && test {
+LL |     match test && test {
    |           ^^^^^^^^^^^^
    |
-   = note: #[deny(eq_op)] on by default
+   = note: #[deny(clippy::eq_op)] on by default
 
 error: you seem to be trying to match on a boolean expression
-  --> $DIR/match_bool.rs:30:5
+  --> $DIR/match_bool.rs:36:5
+   |
+LL | /     match test {
+LL | |         false => {
+LL | |             println!("Noooo!");
+LL | |         },
+...  |
+LL | |         },
+LL | |     };
+   | |_____^
+help: consider using an if/else expression
+   |
+LL |     if test {
+LL |     println!("Yes!");
+LL | } else {
+LL |     println!("Noooo!");
+LL | };
    |
-30 | /     match test {
-31 | |         false => { println!("Noooo!"); }
-32 | |         true => { println!("Yes!"); }
-33 | |     };
-   | |_____^ help: consider using an if/else expression: `if test { println!("Yes!"); } else { println!("Noooo!"); }`
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs
new file mode 100644 (file)
index 0000000..978ac51
--- /dev/null
@@ -0,0 +1,66 @@
+#![feature(exclusive_range_pattern)]
+#![warn(clippy::match_overlapping_arm)]
+#![allow(clippy::redundant_pattern_matching)]
+
+/// Tests for match_overlapping_arm
+
+fn overlapping() {
+    const FOO: u64 = 2;
+
+    match 42 {
+        0...10 => println!("0 ... 10"),
+        0...11 => println!("0 ... 11"),
+        _ => (),
+    }
+
+    match 42 {
+        0...5 => println!("0 ... 5"),
+        6...7 => println!("6 ... 7"),
+        FOO...11 => println!("0 ... 11"),
+        _ => (),
+    }
+
+    match 42 {
+        2 => println!("2"),
+        0...5 => println!("0 ... 5"),
+        _ => (),
+    }
+
+    match 42 {
+        2 => println!("2"),
+        0...2 => println!("0 ... 2"),
+        _ => (),
+    }
+
+    match 42 {
+        0...10 => println!("0 ... 10"),
+        11...50 => println!("11 ... 50"),
+        _ => (),
+    }
+
+    match 42 {
+        2 => println!("2"),
+        0..2 => println!("0 .. 2"),
+        _ => (),
+    }
+
+    match 42 {
+        0..10 => println!("0 .. 10"),
+        10..50 => println!("10 .. 50"),
+        _ => (),
+    }
+
+    match 42 {
+        0..11 => println!("0 .. 11"),
+        0...11 => println!("0 ... 11"),
+        _ => (),
+    }
+
+    if let None = Some(42) {
+        // nothing
+    } else if let None = Some(42) {
+        // another nothing :-)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/match_overlapping_arm.stderr b/tests/ui/match_overlapping_arm.stderr
new file mode 100644 (file)
index 0000000..14eb378
--- /dev/null
@@ -0,0 +1,63 @@
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:11:9
+   |
+LL |         0...10 => println!("0 ... 10"),
+   |         ^^^^^^
+   |
+   = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:12:9
+   |
+LL |         0...11 => println!("0 ... 11"),
+   |         ^^^^^^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:17:9
+   |
+LL |         0...5 => println!("0 ... 5"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:19:9
+   |
+LL |         FOO...11 => println!("0 ... 11"),
+   |         ^^^^^^^^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:25:9
+   |
+LL |         0...5 => println!("0 ... 5"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:24:9
+   |
+LL |         2 => println!("2"),
+   |         ^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:31:9
+   |
+LL |         0...2 => println!("0 ... 2"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:30:9
+   |
+LL |         2 => println!("2"),
+   |         ^
+
+error: some ranges overlap
+  --> $DIR/match_overlapping_arm.rs:54:9
+   |
+LL |         0..11 => println!("0 .. 11"),
+   |         ^^^^^
+   |
+note: overlaps with this
+  --> $DIR/match_overlapping_arm.rs:55:9
+   |
+LL |         0...11 => println!("0 ... 11"),
+   |         ^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs
new file mode 100644 (file)
index 0000000..8a7588f
--- /dev/null
@@ -0,0 +1,113 @@
+#![allow(
+    clippy::blacklisted_name,
+    clippy::collapsible_if,
+    clippy::cognitive_complexity,
+    clippy::eq_op,
+    clippy::needless_continue,
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::zero_divided_by_zero,
+    clippy::unused_unit
+)]
+
+fn bar<T>(_: T) {}
+fn foo() -> bool {
+    unimplemented!()
+}
+
+pub enum Abc {
+    A,
+    B,
+    C,
+}
+
+#[warn(clippy::match_same_arms)]
+#[allow(clippy::unused_unit)]
+fn match_same_arms() {
+    let _ = match 42 {
+        42 => {
+            foo();
+            let mut a = 42 + [23].len() as i32;
+            if true {
+                a += 7;
+            }
+            a = -31 - a;
+            a
+        },
+        _ => {
+            //~ ERROR match arms have same body
+            foo();
+            let mut a = 42 + [23].len() as i32;
+            if true {
+                a += 7;
+            }
+            a = -31 - a;
+            a
+        },
+    };
+
+    let _ = match Abc::A {
+        Abc::A => 0,
+        Abc::B => 1,
+        _ => 0, //~ ERROR match arms have same body
+    };
+
+    let _ = match 42 {
+        42 => foo(),
+        51 => foo(), //~ ERROR match arms have same body
+        _ => true,
+    };
+
+    let _ = match Some(42) {
+        Some(_) => 24,
+        None => 24, //~ ERROR match arms have same body
+    };
+
+    let _ = match Some(42) {
+        Some(foo) => 24,
+        None => 24,
+    };
+
+    let _ = match Some(42) {
+        Some(42) => 24,
+        Some(a) => 24, // bindings are different
+        None => 0,
+    };
+
+    let _ = match Some(42) {
+        Some(a) if a > 0 => 24,
+        Some(a) => 24, // one arm has a guard
+        None => 0,
+    };
+
+    match (Some(42), Some(42)) {
+        (Some(a), None) => bar(a),
+        (None, Some(a)) => bar(a), //~ ERROR match arms have same body
+        _ => (),
+    }
+
+    match (Some(42), Some(42)) {
+        (Some(a), ..) => bar(a),
+        (.., Some(a)) => bar(a), //~ ERROR match arms have same body
+        _ => (),
+    }
+
+    match (1, 2, 3) {
+        (1, .., 3) => 42,
+        (.., 3) => 42, //~ ERROR match arms have same body
+        _ => 0,
+    };
+
+    let _ = match Some(()) {
+        Some(()) => 0.0,
+        None => -0.0,
+    };
+
+    match (Some(42), Some("")) {
+        (Some(a), None) => bar(a),
+        (None, Some(a)) => bar(a), // bindings have different types
+        _ => (),
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr
new file mode 100644 (file)
index 0000000..9389e48
--- /dev/null
@@ -0,0 +1,143 @@
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:37:14
+   |
+LL |           _ => {
+   |  ______________^
+LL | |             //~ ERROR match arms have same body
+LL | |             foo();
+LL | |             let mut a = 42 + [23].len() as i32;
+...  |
+LL | |             a
+LL | |         },
+   | |_________^
+   |
+   = note: `-D clippy::match-same-arms` implied by `-D warnings`
+note: same as this
+  --> $DIR/match_same_arms.rs:28:15
+   |
+LL |           42 => {
+   |  _______________^
+LL | |             foo();
+LL | |             let mut a = 42 + [23].len() as i32;
+LL | |             if true {
+...  |
+LL | |             a
+LL | |         },
+   | |_________^
+note: `42` has the same arm body as the `_` wildcard, consider removing it`
+  --> $DIR/match_same_arms.rs:28:15
+   |
+LL |           42 => {
+   |  _______________^
+LL | |             foo();
+LL | |             let mut a = 42 + [23].len() as i32;
+LL | |             if true {
+...  |
+LL | |             a
+LL | |         },
+   | |_________^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:52:14
+   |
+LL |         _ => 0, //~ ERROR match arms have same body
+   |              ^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:50:19
+   |
+LL |         Abc::A => 0,
+   |                   ^
+note: `Abc::A` has the same arm body as the `_` wildcard, consider removing it`
+  --> $DIR/match_same_arms.rs:50:19
+   |
+LL |         Abc::A => 0,
+   |                   ^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:57:15
+   |
+LL |         51 => foo(), //~ ERROR match arms have same body
+   |               ^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:56:15
+   |
+LL |         42 => foo(),
+   |               ^^^^^
+note: consider refactoring into `42 | 51`
+  --> $DIR/match_same_arms.rs:56:15
+   |
+LL |         42 => foo(),
+   |               ^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:63:17
+   |
+LL |         None => 24, //~ ERROR match arms have same body
+   |                 ^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:62:20
+   |
+LL |         Some(_) => 24,
+   |                    ^^
+note: consider refactoring into `Some(_) | None`
+  --> $DIR/match_same_arms.rs:62:20
+   |
+LL |         Some(_) => 24,
+   |                    ^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:85:28
+   |
+LL |         (None, Some(a)) => bar(a), //~ ERROR match arms have same body
+   |                            ^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:84:28
+   |
+LL |         (Some(a), None) => bar(a),
+   |                            ^^^^^^
+note: consider refactoring into `(Some(a), None) | (None, Some(a))`
+  --> $DIR/match_same_arms.rs:84:28
+   |
+LL |         (Some(a), None) => bar(a),
+   |                            ^^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:91:26
+   |
+LL |         (.., Some(a)) => bar(a), //~ ERROR match arms have same body
+   |                          ^^^^^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:90:26
+   |
+LL |         (Some(a), ..) => bar(a),
+   |                          ^^^^^^
+note: consider refactoring into `(Some(a), ..) | (.., Some(a))`
+  --> $DIR/match_same_arms.rs:90:26
+   |
+LL |         (Some(a), ..) => bar(a),
+   |                          ^^^^^^
+
+error: this `match` has identical arm bodies
+  --> $DIR/match_same_arms.rs:97:20
+   |
+LL |         (.., 3) => 42, //~ ERROR match arms have same body
+   |                    ^^
+   |
+note: same as this
+  --> $DIR/match_same_arms.rs:96:23
+   |
+LL |         (1, .., 3) => 42,
+   |                       ^^
+note: consider refactoring into `(1, .., 3) | (.., 3)`
+  --> $DIR/match_same_arms.rs:96:23
+   |
+LL |         (1, .., 3) => 42,
+   |                       ^^
+
+error: aborting due to 7 previous errors
+
index e339aeb9c6a6043c1b460a576f9c8de9909b9bcc..0360cc739c8142298e5c0bade56ef42f2419aef5 100644 (file)
@@ -1,28 +1,9 @@
-
 #![feature(exclusive_range_pattern)]
+#![warn(clippy::all)]
+#![allow(unused, clippy::redundant_pattern_matching, clippy::too_many_lines)]
+#![warn(clippy::match_same_arms)]
 
-
-#![warn(clippy)]
-#![allow(unused, if_let_redundant_pattern_matching)]
-#![warn(single_match_else, match_same_arms)]
-
-enum ExprNode {
-    ExprAddrOf,
-    Butterflies,
-    Unicorns,
-}
-
-static NODE: ExprNode = ExprNode::Unicorns;
-
-fn dummy() {
-}
-
-fn unwrap_addr() -> Option<&'static ExprNode> {
-    match ExprNode::Butterflies {
-        ExprNode::ExprAddrOf => Some(&NODE),
-        _ => { let x = 5; None },
-    }
-}
+fn dummy() {}
 
 fn ref_pats() {
     {
@@ -31,23 +12,24 @@ fn ref_pats() {
             &Some(v) => println!("{:?}", v),
             &None => println!("none"),
         }
-        match v {  // this doesn't trigger, we have a different pattern
+        match v {
+            // This doesn't trigger; we have a different pattern.
             &Some(v) => println!("some"),
             other => println!("other"),
         }
     }
-    let tup =(1, 2);
+    let tup = &(1, 2);
     match tup {
         &(v, 1) => println!("{}", v),
         _ => println!("none"),
     }
-    // special case: using & both in expr and pats
+    // Special case: using `&` both in expr and pats.
     let w = Some(0);
     match &w {
         &Some(v) => println!("{:?}", v),
         &None => println!("none"),
     }
-    // false positive: only wildcard pattern
+    // False positive: only wildcard pattern.
     let w = Some(0);
     match w {
         _ => println!("none"),
@@ -64,163 +46,119 @@ fn ref_pats() {
     }
 }
 
-fn overlapping() {
-    const FOO : u64 = 2;
-
-    match 42 {
-        0 ... 10 => println!("0 ... 10"),
-        0 ... 11 => println!("0 ... 11"),
-        _ => (),
-    }
-
-    match 42 {
-        0 ... 5 => println!("0 ... 5"),
-        6 ... 7 => println!("6 ... 7"),
-        FOO ... 11 => println!("0 ... 11"),
-        _ => (),
-    }
-
-    match 42 {
-        2 => println!("2"),
-        0 ... 5 => println!("0 ... 5"),
-        _ => (),
-    }
-
-    match 42 {
-        2 => println!("2"),
-        0 ... 2 => println!("0 ... 2"),
-        _ => (),
-    }
-
-    match 42 {
-        0 ... 10 => println!("0 ... 10"),
-        11 ... 50 => println!("11 ... 50"),
-        _ => (),
-    }
-
-    match 42 {
-        2 => println!("2"),
-        0 .. 2 => println!("0 .. 2"),
-        _ => (),
-    }
-
-    match 42 {
-        0 .. 10 => println!("0 .. 10"),
-        10 .. 50 => println!("10 .. 50"),
-        _ => (),
-    }
-
-    match 42 {
-        0 .. 11 => println!("0 .. 11"),
-        0 ... 11 => println!("0 ... 11"),
-        _ => (),
-    }
-
-    if let None = Some(42) {
-        // nothing
-    } else if let None = Some(42) {
-        // another nothing :-)
-    }
-}
-
 fn match_wild_err_arm() {
     let x: Result<i32, &str> = Ok(3);
 
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => panic!("err")
+        Err(_) => panic!("err"),
     }
 
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => {panic!()}
+        Err(_) => panic!(),
     }
 
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => {panic!();}
+        Err(_) => {
+            panic!();
+        },
     }
 
-    // allowed when not with `panic!` block
+    // Allowed when not with `panic!` block.
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => println!("err")
+        Err(_) => println!("err"),
     }
 
-    // allowed when used with `unreachable!`
+    // Allowed when used with `unreachable!`.
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => {unreachable!()}
+        Err(_) => unreachable!(),
     }
 
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => unreachable!()
+        Err(_) => unreachable!(),
     }
 
     match x {
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => {unreachable!();}
+        Err(_) => {
+            unreachable!();
+        },
     }
 
-    // no warning because of the guard
+    // No warning because of the guard.
     match x {
-        Ok(x) if x*x == 64 => println!("ok"),
+        Ok(x) if x * x == 64 => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => println!("err")
+        Err(_) => println!("err"),
     }
 
-    // this used to be a false positive, see #1996
+    // This used to be a false positive; see issue #1996.
     match x {
         Ok(3) => println!("ok"),
-        Ok(x) if x*x == 64 => println!("ok 64"),
+        Ok(x) if x * x == 64 => println!("ok 64"),
         Ok(_) => println!("ok"),
-        Err(_) => println!("err")
+        Err(_) => println!("err"),
     }
 
     match (x, Some(1i32)) {
         (Ok(x), Some(_)) => println!("ok {}", x),
         (Ok(_), Some(x)) => println!("ok {}", x),
-        _ => println!("err")
+        _ => println!("err"),
     }
 
-    // no warning because of the different types for x
+    // No warning; different types for `x`.
     match (x, Some(1.0f64)) {
         (Ok(x), Some(_)) => println!("ok {}", x),
         (Ok(_), Some(x)) => println!("ok {}", x),
-        _ => println!("err")
+        _ => println!("err"),
     }
 
-    // because of a bug, no warning was generated for this case before #2251
+    // Because of a bug, no warning was generated for this case before #2251.
     match x {
         Ok(_tmp) => println!("ok"),
         Ok(3) => println!("ok"),
         Ok(_) => println!("ok"),
-        Err(_) => {unreachable!();}
+        Err(_) => {
+            unreachable!();
+        },
     }
 }
 
-fn match_as_ref() {
-    let owned: Option<()> = None;
-    let borrowed: Option<&()> = match owned {
-        None => None,
-        Some(ref v) => Some(v),
-    };
+macro_rules! foo_variant(
+    ($idx:expr) => (Foo::get($idx).unwrap())
+);
 
-    let mut mut_owned: Option<()> = None;
-    let borrow_mut: Option<&mut ()> = match mut_owned {
-        None => None,
-        Some(ref mut v) => Some(v),
-    };
+enum Foo {
+    A,
+    B,
+}
 
+impl Foo {
+    fn get(idx: u8) -> Option<&'static Self> {
+        match idx {
+            0 => Some(&Foo::A),
+            1 => Some(&Foo::B),
+            _ => None,
+        }
+    }
 }
 
 fn main() {
+    // ICE #3719
+    match foo_variant!(0) {
+        &Foo::A => println!("A"),
+        _ => println!("Wild"),
+    }
 }
index 5bfc3271c4506c3f64106946de46402b55eeb8cd..27438258d2325d024e73982c28ccf382c5eaa574 100644 (file)
-error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/matches.rs:21:5
-   |
-21 | /     match ExprNode::Butterflies {
-22 | |         ExprNode::ExprAddrOf => Some(&NODE),
-23 | |         _ => { let x = 5; None },
-24 | |     }
-   | |_____^ help: try this: `if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { let x = 5; None }`
-   |
-   = note: `-D single-match-else` implied by `-D warnings`
-
 error: you don't need to add `&` to all patterns
-  --> $DIR/matches.rs:30:9
+  --> $DIR/matches.rs:11:9
    |
-30 | /         match v {
-31 | |             &Some(v) => println!("{:?}", v),
-32 | |             &None => println!("none"),
-33 | |         }
+LL | /         match v {
+LL | |             &Some(v) => println!("{:?}", v),
+LL | |             &None => println!("none"),
+LL | |         }
    | |_________^
    |
-   = note: `-D match-ref-pats` implied by `-D warnings`
+   = note: `-D clippy::match-ref-pats` implied by `-D warnings`
 help: instead of prefixing all patterns with `&`, you can dereference the expression
    |
-30 |         match *v {
-31 |             Some(v) => println!("{:?}", v),
-32 |             None => println!("none"),
-   |
-
-error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/matches.rs:40:5
-   |
-40 | /     match tup {
-41 | |         &(v, 1) => println!("{}", v),
-42 | |         _ => println!("none"),
-43 | |     }
-   | |_____^
-help: try this
-   |
-40 |     if let &(v, 1) = tup {
-41 | # [ cfg ( not ( stage0 ) ) ] {
-42 | ( $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ) ; } # [
-43 | cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( $ ( $ arg ) * ) ) } } else {
-44 | ( $ crate :: io :: _print ( format_args_nl ! ( $ ( $ arg ) * ) ) ) ; }
+LL |         match *v {
+LL |             Some(v) => println!("{:?}", v),
+LL |             None => println!("none"),
    |
 
 error: you don't need to add `&` to all patterns
-  --> $DIR/matches.rs:40:5
+  --> $DIR/matches.rs:22:5
    |
-40 | /     match tup {
-41 | |         &(v, 1) => println!("{}", v),
-42 | |         _ => println!("none"),
-43 | |     }
+LL | /     match tup {
+LL | |         &(v, 1) => println!("{}", v),
+LL | |         _ => println!("none"),
+LL | |     }
    | |_____^
 help: instead of prefixing all patterns with `&`, you can dereference the expression
    |
-40 |     match *tup {
-41 |         (v, 1) => println!("{}", v),
+LL |     match *tup {
+LL |         (v, 1) => println!("{}", v),
    |
 
 error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/matches.rs:46:5
+  --> $DIR/matches.rs:28:5
    |
-46 | /     match &w {
-47 | |         &Some(v) => println!("{:?}", v),
-48 | |         &None => println!("none"),
-49 | |     }
+LL | /     match &w {
+LL | |         &Some(v) => println!("{:?}", v),
+LL | |         &None => println!("none"),
+LL | |     }
    | |_____^
 help: try
    |
-46 |     match w {
-47 |         Some(v) => println!("{:?}", v),
-48 |         None => println!("none"),
+LL |     match w {
+LL |         Some(v) => println!("{:?}", v),
+LL |         None => println!("none"),
    |
 
 error: you don't need to add `&` to all patterns
-  --> $DIR/matches.rs:57:5
+  --> $DIR/matches.rs:39:5
    |
-57 | /     if let &None = a {
-58 | |         println!("none");
-59 | |     }
+LL | /     if let &None = a {
+LL | |         println!("none");
+LL | |     }
    | |_____^
 help: instead of prefixing all patterns with `&`, you can dereference the expression
    |
-57 |     if let None = *a {
+LL |     if let None = *a {
    |            ^^^^   ^^
 
 error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/matches.rs:62:5
+  --> $DIR/matches.rs:44:5
    |
-62 | /     if let &None = &b {
-63 | |         println!("none");
-64 | |     }
+LL | /     if let &None = &b {
+LL | |         println!("none");
+LL | |     }
    | |_____^
 help: try
    |
-62 |     if let None = b {
+LL |     if let None = b {
    |            ^^^^   ^
 
-error: some ranges overlap
-  --> $DIR/matches.rs:71:9
-   |
-71 |         0 ... 10 => println!("0 ... 10"),
-   |         ^^^^^^^^
+error: Err(_) will match all errors, maybe not a good idea
+  --> $DIR/matches.rs:55:9
    |
-   = note: `-D match-overlapping-arm` implied by `-D warnings`
-note: overlaps with this
-  --> $DIR/matches.rs:72:9
+LL |         Err(_) => panic!("err"),
+   |         ^^^^^^
    |
-72 |         0 ... 11 => println!("0 ... 11"),
-   |         ^^^^^^^^
+   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+   = note: to remove this warning, match each error separately or use unreachable macro
 
-error: some ranges overlap
-  --> $DIR/matches.rs:77:9
-   |
-77 |         0 ... 5 => println!("0 ... 5"),
-   |         ^^^^^^^
-   |
-note: overlaps with this
-  --> $DIR/matches.rs:79:9
+error: this `match` has identical arm bodies
+  --> $DIR/matches.rs:54:18
    |
-79 |         FOO ... 11 => println!("0 ... 11"),
-   |         ^^^^^^^^^^
-
-error: some ranges overlap
-  --> $DIR/matches.rs:85:9
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
    |
-85 |         0 ... 5 => println!("0 ... 5"),
-   |         ^^^^^^^
+   = note: `-D clippy::match-same-arms` implied by `-D warnings`
+note: same as this
+  --> $DIR/matches.rs:53:18
    |
-note: overlaps with this
-  --> $DIR/matches.rs:84:9
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+note: consider refactoring into `Ok(3) | Ok(_)`
+  --> $DIR/matches.rs:53:18
    |
-84 |         2 => println!("2"),
-   |         ^
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: some ranges overlap
-  --> $DIR/matches.rs:91:9
-   |
-91 |         0 ... 2 => println!("0 ... 2"),
-   |         ^^^^^^^
+error: Err(_) will match all errors, maybe not a good idea
+  --> $DIR/matches.rs:61:9
    |
-note: overlaps with this
-  --> $DIR/matches.rs:90:9
+LL |         Err(_) => panic!(),
+   |         ^^^^^^
    |
-90 |         2 => println!("2"),
-   |         ^
-
-error: some ranges overlap
-   --> $DIR/matches.rs:114:9
-    |
-114 |         0 .. 11 => println!("0 .. 11"),
-    |         ^^^^^^^
-    |
-note: overlaps with this
-   --> $DIR/matches.rs:115:9
-    |
-115 |         0 ... 11 => println!("0 ... 11"),
-    |         ^^^^^^^^
-
-error: Err(_) will match all errors, maybe not a good idea
-   --> $DIR/matches.rs:132:9
-    |
-132 |         Err(_) => panic!("err")
-    |         ^^^^^^
-    |
-    = note: `-D match-wild-err-arm` implied by `-D warnings`
-    = note: to remove this warning, match each error separately or use unreachable macro
+   = note: to remove this warning, match each error separately or use unreachable macro
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:131:18
-    |
-131 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
-    = note: `-D match-same-arms` implied by `-D warnings`
-note: same as this
-   --> $DIR/matches.rs:130:18
-    |
-130 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:130:18
-    |
-130 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
-
-error: Err(_) will match all errors, maybe not a good idea
-   --> $DIR/matches.rs:138:9
-    |
-138 |         Err(_) => {panic!()}
-    |         ^^^^^^
-    |
-    = note: to remove this warning, match each error separately or use unreachable macro
-
-error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:137:18
-    |
-137 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:60:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:136:18
-    |
-136 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:59:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:136:18
-    |
-136 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:59:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: Err(_) will match all errors, maybe not a good idea
-   --> $DIR/matches.rs:144:9
-    |
-144 |         Err(_) => {panic!();}
-    |         ^^^^^^
-    |
-    = note: to remove this warning, match each error separately or use unreachable macro
+  --> $DIR/matches.rs:67:9
+   |
+LL |         Err(_) => {
+   |         ^^^^^^
+   |
+   = note: to remove this warning, match each error separately or use unreachable macro
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:143:18
-    |
-143 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:66:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:142:18
-    |
-142 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:65:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:142:18
-    |
-142 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:65:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:150:18
-    |
-150 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:75:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:149:18
-    |
-149 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:74:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:149:18
-    |
-149 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:74:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:157:18
-    |
-157 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:82:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:156:18
-    |
-156 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:81:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:156:18
-    |
-156 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:81:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:163:18
-    |
-163 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:88:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:162:18
-    |
-162 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:87:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:162:18
-    |
-162 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:87:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:169:18
-    |
-169 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:94:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:168:18
-    |
-168 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:93:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:168:18
-    |
-168 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:93:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:190:29
-    |
-190 |         (Ok(_), Some(x)) => println!("ok {}", x),
-    |                             ^^^^^^^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:117:29
+   |
+LL |         (Ok(_), Some(x)) => println!("ok {}", x),
+   |                             ^^^^^^^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:189:29
-    |
-189 |         (Ok(x), Some(_)) => println!("ok {}", x),
-    |                             ^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:116:29
+   |
+LL |         (Ok(x), Some(_)) => println!("ok {}", x),
+   |                             ^^^^^^^^^^^^^^^^^^^^
 note: consider refactoring into `(Ok(x), Some(_)) | (Ok(_), Some(x))`
-   --> $DIR/matches.rs:189:29
-    |
-189 |         (Ok(x), Some(_)) => println!("ok {}", x),
-    |                             ^^^^^^^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+  --> $DIR/matches.rs:116:29
+   |
+LL |         (Ok(x), Some(_)) => println!("ok {}", x),
+   |                             ^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: this `match` has identical arm bodies
-   --> $DIR/matches.rs:205:18
-    |
-205 |         Ok(_) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    |
+  --> $DIR/matches.rs:132:18
+   |
+LL |         Ok(_) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   |
 note: same as this
-   --> $DIR/matches.rs:204:18
-    |
-204 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
+  --> $DIR/matches.rs:131:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
 note: consider refactoring into `Ok(3) | Ok(_)`
-   --> $DIR/matches.rs:204:18
-    |
-204 |         Ok(3) => println!("ok"),
-    |                  ^^^^^^^^^^^^^^
-    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
-
-error: use as_ref() instead
-   --> $DIR/matches.rs:212:33
-    |
-212 |       let borrowed: Option<&()> = match owned {
-    |  _________________________________^
-213 | |         None => None,
-214 | |         Some(ref v) => Some(v),
-215 | |     };
-    | |_____^ help: try this: `owned.as_ref()`
-    |
-    = note: `-D match-as-ref` implied by `-D warnings`
+  --> $DIR/matches.rs:131:18
+   |
+LL |         Ok(3) => println!("ok"),
+   |                  ^^^^^^^^^^^^^^
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: use as_mut() instead
-   --> $DIR/matches.rs:218:39
-    |
-218 |       let borrow_mut: Option<&mut ()> = match mut_owned {
-    |  _______________________________________^
-219 | |         None => None,
-220 | |         Some(ref mut v) => Some(v),
-221 | |     };
-    | |_____^ help: try this: `mut_owned.as_mut()`
+error: you don't need to add `&` to all patterns
+  --> $DIR/matches.rs:160:5
+   |
+LL | /     match foo_variant!(0) {
+LL | |         &Foo::A => println!("A"),
+LL | |         _ => println!("Wild"),
+LL | |     }
+   | |_____^
+help: instead of prefixing all patterns with `&`, you can dereference the expression
+   |
+LL |     match *foo_variant!(0) {
+LL |         Foo::A => println!("A"),
+   |
 
-error: aborting due to 26 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/tests/ui/mem_discriminant.rs b/tests/ui/mem_discriminant.rs
new file mode 100644 (file)
index 0000000..81f1628
--- /dev/null
@@ -0,0 +1,47 @@
+#![deny(clippy::mem_discriminant_non_enum)]
+
+use std::mem;
+
+enum Foo {
+    One(usize),
+    Two(u8),
+}
+
+struct A(Foo);
+
+fn main() {
+    // bad
+    mem::discriminant(&"hello");
+    mem::discriminant(&&Some(2));
+    mem::discriminant(&&None::<u8>);
+    mem::discriminant(&&Foo::One(5));
+    mem::discriminant(&&Foo::Two(5));
+    mem::discriminant(&A(Foo::One(0)));
+
+    let ro = &Some(3);
+    let rro = &ro;
+    mem::discriminant(&ro);
+    mem::discriminant(rro);
+    mem::discriminant(&rro);
+
+    macro_rules! mem_discriminant_but_in_a_macro {
+        ($param:expr) => {
+            mem::discriminant($param)
+        };
+    }
+
+    mem_discriminant_but_in_a_macro!(&rro);
+
+    let rrrrro = &&&rro;
+    mem::discriminant(&rrrrro);
+    mem::discriminant(*rrrrro);
+
+    // ok
+    mem::discriminant(&Some(2));
+    mem::discriminant(&None::<u8>);
+    mem::discriminant(&Foo::One(5));
+    mem::discriminant(&Foo::Two(5));
+    mem::discriminant(ro);
+    mem::discriminant(*rro);
+    mem::discriminant(****rrrrro);
+}
diff --git a/tests/ui/mem_discriminant.stderr b/tests/ui/mem_discriminant.stderr
new file mode 100644 (file)
index 0000000..2955454
--- /dev/null
@@ -0,0 +1,104 @@
+error: calling `mem::discriminant` on non-enum type `&str`
+  --> $DIR/mem_discriminant.rs:14:5
+   |
+LL |     mem::discriminant(&"hello");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/mem_discriminant.rs:1:9
+   |
+LL | #![deny(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:15:5
+   |
+LL |     mem::discriminant(&&Some(2));
+   |     ^^^^^^^^^^^^^^^^^^---------^
+   |                       |
+   |                       help: try dereferencing: `&Some(2)`
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<u8>`
+  --> $DIR/mem_discriminant.rs:16:5
+   |
+LL |     mem::discriminant(&&None::<u8>);
+   |     ^^^^^^^^^^^^^^^^^^------------^
+   |                       |
+   |                       help: try dereferencing: `&None::<u8>`
+
+error: calling `mem::discriminant` on non-enum type `&Foo`
+  --> $DIR/mem_discriminant.rs:17:5
+   |
+LL |     mem::discriminant(&&Foo::One(5));
+   |     ^^^^^^^^^^^^^^^^^^-------------^
+   |                       |
+   |                       help: try dereferencing: `&Foo::One(5)`
+
+error: calling `mem::discriminant` on non-enum type `&Foo`
+  --> $DIR/mem_discriminant.rs:18:5
+   |
+LL |     mem::discriminant(&&Foo::Two(5));
+   |     ^^^^^^^^^^^^^^^^^^-------------^
+   |                       |
+   |                       help: try dereferencing: `&Foo::Two(5)`
+
+error: calling `mem::discriminant` on non-enum type `A`
+  --> $DIR/mem_discriminant.rs:19:5
+   |
+LL |     mem::discriminant(&A(Foo::One(0)));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:23:5
+   |
+LL |     mem::discriminant(&ro);
+   |     ^^^^^^^^^^^^^^^^^^---^
+   |                       |
+   |                       help: try dereferencing: `ro`
+
+error: calling `mem::discriminant` on non-enum type `&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:24:5
+   |
+LL |     mem::discriminant(rro);
+   |     ^^^^^^^^^^^^^^^^^^---^
+   |                       |
+   |                       help: try dereferencing: `*rro`
+
+error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:25:5
+   |
+LL |     mem::discriminant(&rro);
+   |     ^^^^^^^^^^^^^^^^^^----^
+   |                       |
+   |                       help: try dereferencing: `*rro`
+
+error: calling `mem::discriminant` on non-enum type `&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:29:13
+   |
+LL |             mem::discriminant($param)
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     mem_discriminant_but_in_a_macro!(&rro);
+   |     ---------------------------------------
+   |     |                                |
+   |     |                                help: try dereferencing: `*rro`
+   |     in this macro invocation
+
+error: calling `mem::discriminant` on non-enum type `&&&&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:36:5
+   |
+LL |     mem::discriminant(&rrrrro);
+   |     ^^^^^^^^^^^^^^^^^^-------^
+   |                       |
+   |                       help: try dereferencing: `****rrrrro`
+
+error: calling `mem::discriminant` on non-enum type `&&&std::option::Option<i32>`
+  --> $DIR/mem_discriminant.rs:37:5
+   |
+LL |     mem::discriminant(*rrrrro);
+   |     ^^^^^^^^^^^^^^^^^^-------^
+   |                       |
+   |                       help: try dereferencing: `****rrrrro`
+
+error: aborting due to 12 previous errors
+
index 991a402e2076c67fc536f76a65b5b4e5c2f846e7..e5b35c098a23969a2e47ee732d03aaae7ea23c35 100644 (file)
@@ -1,15 +1,11 @@
-
-
-
-
-use std::sync::Arc;
 use std::rc::Rc;
+use std::sync::Arc;
 
-use std::mem::forget as forgetSomething;
 use std::mem as memstuff;
+use std::mem::forget as forgetSomething;
 
-#[warn(mem_forget)]
-#[allow(forget_copy)]
+#[warn(clippy::mem_forget)]
+#[allow(clippy::forget_copy)]
 fn main() {
     let five: i32 = 5;
     forgetSomething(five);
index 6e7a44694e14f8c3d176d07d190c4ddebf9e4072..16b95a1038a08961f1be2bfd68586994396e4ff6 100644 (file)
@@ -1,21 +1,21 @@
 error: usage of mem::forget on Drop type
-  --> $DIR/mem_forget.rs:18:5
+  --> $DIR/mem_forget.rs:14:5
    |
-18 |     memstuff::forget(six);
+LL |     memstuff::forget(six);
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D mem-forget` implied by `-D warnings`
+   = note: `-D clippy::mem-forget` implied by `-D warnings`
 
 error: usage of mem::forget on Drop type
-  --> $DIR/mem_forget.rs:21:5
+  --> $DIR/mem_forget.rs:17:5
    |
-21 |     std::mem::forget(seven);
+LL |     std::mem::forget(seven);
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: usage of mem::forget on Drop type
-  --> $DIR/mem_forget.rs:24:5
+  --> $DIR/mem_forget.rs:20:5
    |
-24 |     forgetSomething(eight);
+LL |     forgetSomething(eight);
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed
new file mode 100644 (file)
index 0000000..4e47ac9
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2014-2019 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(clippy::all, clippy::style, clippy::mem_replace_option_with_none)]
+
+use std::mem;
+
+fn main() {
+    let mut an_option = Some(1);
+    let _ = an_option.take();
+    let an_option = &mut Some(1);
+    let _ = an_option.take();
+}
diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs
new file mode 100644 (file)
index 0000000..6824ab1
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2014-2019 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+#![allow(unused_imports)]
+#![warn(clippy::all, clippy::style, clippy::mem_replace_option_with_none)]
+
+use std::mem;
+
+fn main() {
+    let mut an_option = Some(1);
+    let _ = mem::replace(&mut an_option, None);
+    let an_option = &mut Some(1);
+    let _ = mem::replace(an_option, None);
+}
diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr
new file mode 100644 (file)
index 0000000..791c4d7
--- /dev/null
@@ -0,0 +1,16 @@
+error: replacing an `Option` with `None`
+  --> $DIR/mem_replace.rs:18:13
+   |
+LL |     let _ = mem::replace(&mut an_option, None);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
+   |
+   = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
+
+error: replacing an `Option` with `None`
+  --> $DIR/mem_replace.rs:20:13
+   |
+LL |     let _ = mem::replace(an_option, None);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
+
+error: aborting due to 2 previous errors
+
index 7f0da364c7a35c8604230ae6e0079ae59bb919b3..3a8aedcd65980492ef0b6d3f5be051cf26a7d76f 100644 (file)
@@ -1,39 +1,83 @@
-
-#![feature(const_fn)]
-
-#![warn(clippy, clippy_pedantic, option_unwrap_used)]
-#![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default,
-    new_without_default_derive, missing_docs_in_private_items, needless_pass_by_value,
-    default_trait_access, use_self)]
+// aux-build:option_helpers.rs
+
+#![warn(clippy::all, clippy::pedantic, clippy::option_unwrap_used)]
+#![allow(
+    clippy::blacklisted_name,
+    unused,
+    clippy::print_stdout,
+    clippy::non_ascii_literal,
+    clippy::new_without_default,
+    clippy::missing_docs_in_private_items,
+    clippy::needless_pass_by_value,
+    clippy::default_trait_access,
+    clippy::use_self,
+    clippy::new_ret_no_self,
+    clippy::useless_format
+)]
+
+#[macro_use]
+extern crate option_helpers;
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
 use std::collections::HashSet;
 use std::collections::VecDeque;
-use std::ops::Mul;
 use std::iter::FromIterator;
+use std::ops::Mul;
 use std::rc::{self, Rc};
 use std::sync::{self, Arc};
 
+use option_helpers::IteratorFalsePositives;
+
 pub struct T;
 
 impl T {
-    pub fn add(self, other: T) -> T { self }
+    pub fn add(self, other: T) -> T {
+        self
+    }
+
+    // no error, not public interface
+    pub(crate) fn drop(&mut self) {}
+
+    // no error, private function
+    fn neg(self) -> Self {
+        self
+    }
+
+    // no error, private function
+    fn eq(&self, other: T) -> bool {
+        true
+    }
+
+    // No error; self is a ref.
+    fn sub(&self, other: T) -> &T {
+        self
+    }
 
-    pub(crate) fn drop(&mut self) { } // no error, not public interfact
-    fn neg(self) -> Self { self } // no error, private function
-    fn eq(&self, other: T) -> bool { true } // no error, private function
+    // No error; different number of arguments.
+    fn div(self) -> T {
+        self
+    }
 
-    fn sub(&self, other: T) -> &T { self } // no error, self is a ref
-    fn div(self) -> T { self } // no error, different #arguments
-    fn rem(self, other: T) { } // no error, wrong return type
+    // No error; wrong return type.
+    fn rem(self, other: T) {}
+
+    // Fine
+    fn into_u32(self) -> u32 {
+        0
+    }
 
-    fn into_u32(self) -> u32 { 0 } // fine
-    fn into_u16(&self) -> u16 { 0 }
+    fn into_u16(&self) -> u16 {
+        0
+    }
 
-    fn to_something(self) -> u32 { 0 }
+    fn to_something(self) -> u32 {
+        0
+    }
 
-    fn new(self) {}
+    fn new(self) -> Self {
+        unimplemented!();
+    }
 }
 
 struct Lt<'a> {
@@ -41,9 +85,11 @@ struct Lt<'a> {
 }
 
 impl<'a> Lt<'a> {
-    // The lifetime is different, but that’s irrelevant, see #734
-    #[allow(needless_lifetimes)]
-    pub fn new<'b>(s: &'b str) -> Lt<'b> { unimplemented!() }
+    // The lifetime is different, but that’s irrelevant; see issue #734.
+    #[allow(clippy::needless_lifetimes)]
+    pub fn new<'b>(s: &'b str) -> Lt<'b> {
+        unimplemented!()
+    }
 }
 
 struct Lt2<'a> {
@@ -51,8 +97,10 @@ struct Lt2<'a> {
 }
 
 impl<'a> Lt2<'a> {
-    // The lifetime is different, but that’s irrelevant, see #734
-    pub fn new(s: &str) -> Lt2 { unimplemented!() }
+    // The lifetime is different, but that’s irrelevant; see issue #734.
+    pub fn new(s: &str) -> Lt2 {
+        unimplemented!()
+    }
 }
 
 struct Lt3<'a> {
@@ -60,51 +108,56 @@ struct Lt3<'a> {
 }
 
 impl<'a> Lt3<'a> {
-    // The lifetime is different, but that’s irrelevant, see #734
-    pub fn new() -> Lt3<'static> { unimplemented!() }
+    // The lifetime is different, but that’s irrelevant; see issue #734.
+    pub fn new() -> Lt3<'static> {
+        unimplemented!()
+    }
 }
 
-#[derive(Clone,Copy)]
+#[derive(Clone, Copy)]
 struct U;
 
 impl U {
-    fn new() -> Self { U }
-    fn to_something(self) -> u32 { 0 } // ok because U is Copy
+    fn new() -> Self {
+        U
+    }
+    // Ok because `U` is `Copy`.
+    fn to_something(self) -> u32 {
+        0
+    }
 }
 
 struct V<T> {
-    _dummy: T
+    _dummy: T,
 }
 
 impl<T> V<T> {
-    fn new() -> Option<V<T>> { None }
+    fn new() -> Option<V<T>> {
+        None
+    }
 }
 
 impl Mul<T> for T {
     type Output = T;
-    fn mul(self, other: T) -> T { self } // no error, obviously
-}
-
-/// Utility macro to test linting behavior in `option_methods()`
-/// The lints included in `option_methods()` should not lint if the call to map is partially
-/// within a macro
-macro_rules! opt_map {
-    ($opt:expr, $map:expr) => {($opt).map($map)};
+    // No error, obviously.
+    fn mul(self, other: T) -> T {
+        self
+    }
 }
 
 /// Checks implementation of the following lints:
 /// * `OPTION_MAP_UNWRAP_OR`
 /// * `OPTION_MAP_UNWRAP_OR_ELSE`
-/// * `OPTION_MAP_OR_NONE`
+#[rustfmt::skip]
 fn option_methods() {
     let opt = Some(1);
 
-    // Check OPTION_MAP_UNWRAP_OR
-    // single line case
+    // Check `OPTION_MAP_UNWRAP_OR`.
+    // Single line case.
     let _ = opt.map(|x| x + 1)
-
-               .unwrap_or(0); // should lint even though this call is on a separate line
-    // multi line cases
+                // Should lint even though this call is on a separate line.
+               .unwrap_or(0);
+    // Multi-line cases.
     let _ = opt.map(|x| {
                         x + 1
                     }
@@ -113,9 +166,9 @@ fn option_methods() {
                .unwrap_or({
                     0
                 });
-    // single line `map(f).unwrap_or(None)` case
+    // Single line `map(f).unwrap_or(None)` case.
     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
-    // multiline `map(f).unwrap_or(None)` cases
+    // Multi-line `map(f).unwrap_or(None)` cases.
     let _ = opt.map(|x| {
         Some(x + 1)
     }
@@ -126,12 +179,19 @@ fn option_methods() {
     // macro case
     let _ = opt_map!(opt, |x| x + 1).unwrap_or(0); // should not lint
 
+    // Should not lint if not copyable
+    let id: String = "identifier".to_string();
+    let _ = Some("prefix").map(|p| format!("{}.{}", p, id)).unwrap_or(id);
+    // ...but DO lint if the `unwrap_or` argument is not used in the `map`
+    let id: String = "identifier".to_string();
+    let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
+
     // Check OPTION_MAP_UNWRAP_OR_ELSE
     // single line case
     let _ = opt.map(|x| x + 1)
-
-               .unwrap_or_else(|| 0); // should lint even though this call is on a separate line
-    // multi line cases
+                // Should lint even though this call is on a separate line.
+               .unwrap_or_else(|| 0);
+    // Multi-line cases.
     let _ = opt.map(|x| {
                         x + 1
                     }
@@ -140,301 +200,70 @@ fn option_methods() {
                .unwrap_or_else(||
                     0
                 );
-    // macro case
-    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); // should not lint
-
-    // Check OPTION_MAP_OR_NONE
-    // single line case
-    let _ = opt.map_or(None, |x| Some(x + 1));
-    // multi line case
-    let _ = opt.map_or(None, |x| {
-                        Some(x + 1)
-                       }
-                );
-}
-
-/// Checks implementation of the following lints:
-/// * `RESULT_MAP_UNWRAP_OR_ELSE`
-fn result_methods() {
-    let res: Result<i32, ()> = Ok(1);
-
-    // Check RESULT_MAP_UNWRAP_OR_ELSE
-    // single line case
-    let _ = res.map(|x| x + 1)
-
-               .unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
-    // multi line cases
-    let _ = res.map(|x| {
-                        x + 1
-                    }
-              ).unwrap_or_else(|e| 0);
-    let _ = res.map(|x| x + 1)
-               .unwrap_or_else(|e|
-                    0
-                );
-    // macro case
-    let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint
-}
-
-/// Struct to generate false positives for things with .iter()
-#[derive(Copy, Clone)]
-struct HasIter;
-
-impl HasIter {
-    fn iter(self) -> IteratorFalsePositives {
-        IteratorFalsePositives { foo: 0 }
-    }
-
-    fn iter_mut(self) -> IteratorFalsePositives {
-        IteratorFalsePositives { foo: 0 }
-    }
-}
-
-/// Struct to generate false positive for Iterator-based lints
-#[derive(Copy, Clone)]
-struct IteratorFalsePositives {
-    foo: u32,
+    // Macro case.
+    // Should not lint.
+    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
 }
 
-impl IteratorFalsePositives {
-    fn filter(self) -> IteratorFalsePositives {
-        self
-    }
-
-    fn next(self) -> IteratorFalsePositives {
-        self
-    }
-
-    fn find(self) -> Option<u32> {
-        Some(self.foo)
-    }
-
-    fn position(self) -> Option<u32> {
-        Some(self.foo)
-    }
-
-    fn rposition(self) -> Option<u32> {
-        Some(self.foo)
-    }
-
-    fn nth(self, n: usize) -> Option<u32> {
-        Some(self.foo)
-    }
-
-    fn skip(self, _: usize) -> IteratorFalsePositives {
-        self
-    }
-}
-
-/// Checks implementation of `FILTER_NEXT` lint
+/// Checks implementation of `FILTER_NEXT` lint.
+#[rustfmt::skip]
 fn filter_next() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
 
-    // check single-line case
+    // Single-line case.
     let _ = v.iter().filter(|&x| *x < 0).next();
 
-    // check multi-line case
+    // Multi-line case.
     let _ = v.iter().filter(|&x| {
                                 *x < 0
                             }
                    ).next();
 
-    // check that we don't lint if the caller is not an Iterator
+    // Check that hat we don't lint if the caller is not an `Iterator`.
     let foo = IteratorFalsePositives { foo: 0 };
     let _ = foo.filter().next();
 }
 
-/// Checks implementation of `SEARCH_IS_SOME` lint
+/// Checks implementation of `SEARCH_IS_SOME` lint.
+#[rustfmt::skip]
 fn search_is_some() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
 
-    // check `find().is_some()`, single-line
+    // Check `find().is_some()`, single-line case.
     let _ = v.iter().find(|&x| *x < 0).is_some();
 
-    // check `find().is_some()`, multi-line
+    // Check `find().is_some()`, multi-line case.
     let _ = v.iter().find(|&x| {
                               *x < 0
                           }
                    ).is_some();
 
-    // check `position().is_some()`, single-line
+    // Check `position().is_some()`, single-line case.
     let _ = v.iter().position(|&x| x < 0).is_some();
 
-    // check `position().is_some()`, multi-line
+    // Check `position().is_some()`, multi-line case.
     let _ = v.iter().position(|&x| {
                                   x < 0
                               }
                    ).is_some();
 
-    // check `rposition().is_some()`, single-line
+    // Check `rposition().is_some()`, single-line case.
     let _ = v.iter().rposition(|&x| x < 0).is_some();
 
-    // check `rposition().is_some()`, multi-line
+    // Check `rposition().is_some()`, multi-line case.
     let _ = v.iter().rposition(|&x| {
                                    x < 0
                                }
                    ).is_some();
 
-    // check that we don't lint if the caller is not an Iterator
+    // Check that we don't lint if the caller is not an `Iterator`.
     let foo = IteratorFalsePositives { foo: 0 };
     let _ = foo.find().is_some();
     let _ = foo.position().is_some();
     let _ = foo.rposition().is_some();
 }
 
-/// Checks implementation of the `OR_FUN_CALL` lint
-fn or_fun_call() {
-    struct Foo;
-
-    impl Foo {
-        fn new() -> Foo { Foo }
-    }
-
-    enum Enum {
-        A(i32),
-    }
-
-    const fn make_const(i: i32) -> i32 { i }
-
-    fn make<T>() -> T { unimplemented!(); }
-
-    let with_enum = Some(Enum::A(1));
-    with_enum.unwrap_or(Enum::A(5));
-
-    let with_const_fn = Some(1);
-    with_const_fn.unwrap_or(make_const(5));
-
-    let with_constructor = Some(vec![1]);
-    with_constructor.unwrap_or(make());
-
-    let with_new = Some(vec![1]);
-    with_new.unwrap_or(Vec::new());
-
-    let with_const_args = Some(vec![1]);
-    with_const_args.unwrap_or(Vec::with_capacity(12));
-
-    let with_err : Result<_, ()> = Ok(vec![1]);
-    with_err.unwrap_or(make());
-
-    let with_err_args : Result<_, ()> = Ok(vec![1]);
-    with_err_args.unwrap_or(Vec::with_capacity(12));
-
-    let with_default_trait = Some(1);
-    with_default_trait.unwrap_or(Default::default());
-
-    let with_default_type = Some(1);
-    with_default_type.unwrap_or(u64::default());
-
-    let with_vec = Some(vec![1]);
-    with_vec.unwrap_or(vec![]);
-
-    // FIXME #944: ~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
-
-    let without_default = Some(Foo);
-    without_default.unwrap_or(Foo::new());
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-
-    let stringy = Some(String::from(""));
-    let _ = stringy.unwrap_or("".to_owned());
-}
-
-/// Checks implementation of the `EXPECT_FUN_CALL` lint
-fn expect_fun_call() {
-    struct Foo;
-
-    impl Foo {
-        fn new() -> Self { Foo }
-
-        fn expect(&self, msg: &str) {
-            panic!("{}", msg)
-        }
-    }
-
-    let with_some = Some("value");
-    with_some.expect("error");
-
-    let with_none: Option<i32> = None;
-    with_none.expect("error");
-
-    let error_code = 123_i32;
-    let with_none_and_format: Option<i32> = None;
-    with_none_and_format.expect(&format!("Error {}: fake error", error_code));
-
-    let with_none_and_as_str: Option<i32> = None;
-    with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
-
-    let with_ok: Result<(), ()> = Ok(());
-    with_ok.expect("error");
-
-    let with_err: Result<(), ()> = Err(());
-    with_err.expect("error");
-
-    let error_code = 123_i32;
-    let with_err_and_format: Result<(), ()> = Err(());
-    with_err_and_format.expect(&format!("Error {}: fake error", error_code));
-
-    let with_err_and_as_str: Result<(), ()> = Err(());
-    with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
-
-    let with_dummy_type = Foo::new();
-    with_dummy_type.expect("another test string");
-
-    let with_dummy_type_and_format = Foo::new();
-    with_dummy_type_and_format.expect(&format!("Error {}: fake error", error_code));
-
-    let with_dummy_type_and_as_str = Foo::new();
-    with_dummy_type_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
-}
-
-/// Checks implementation of `ITER_NTH` lint
-fn iter_nth() {
-    let mut some_vec = vec![0, 1, 2, 3];
-    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
-    let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
-
-    {
-        // Make sure we lint `.iter()` for relevant types
-        let bad_vec = some_vec.iter().nth(3);
-        let bad_slice = &some_vec[..].iter().nth(3);
-        let bad_boxed_slice = boxed_slice.iter().nth(3);
-        let bad_vec_deque = some_vec_deque.iter().nth(3);
-    }
-
-    {
-        // Make sure we lint `.iter_mut()` for relevant types
-        let bad_vec = some_vec.iter_mut().nth(3);
-    }
-    {
-        let bad_slice = &some_vec[..].iter_mut().nth(3);
-    }
-    {
-        let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
-    }
-
-    // Make sure we don't lint for non-relevant types
-    let false_positive = HasIter;
-    let ok = false_positive.iter().nth(3);
-    let ok_mut = false_positive.iter_mut().nth(3);
-}
-
-/// Checks implementation of `ITER_SKIP_NEXT` lint
-fn iter_skip_next() {
-    let mut some_vec = vec![0, 1, 2, 3];
-    let _ = some_vec.iter().skip(42).next();
-    let _ = some_vec.iter().cycle().skip(42).next();
-    let _ = (1..10).skip(10).next();
-    let _ = &some_vec[..].iter().skip(3).next();
-    let foo = IteratorFalsePositives { foo : 0 };
-    let _ = foo.skip(42).next();
-    let _ = foo.filter().skip(42).next();
-}
-
-#[allow(similar_names)]
+#[allow(clippy::similar_names)]
 fn main() {
     let opt = Some(0);
     let _ = opt.unwrap();
index 12665244b9d59488c434587c99e598ec3c83ae5a..4bf53acf01ef294e706ca29b93e361f414e28cdc 100644 (file)
 error: defining a method called `add` on this type; consider implementing the `std::ops::Add` trait or choosing a less ambiguous name
-  --> $DIR/methods.rs:21:5
+  --> $DIR/methods.rs:35:5
    |
-21 |     pub fn add(self, other: T) -> T { self }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     pub fn add(self, other: T) -> T {
+LL | |         self
+LL | |     }
+   | |_____^
    |
-   = note: `-D should-implement-trait` implied by `-D warnings`
+   = note: `-D clippy::should-implement-trait` implied by `-D warnings`
 
 error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-  --> $DIR/methods.rs:32:17
+  --> $DIR/methods.rs:70:17
    |
-32 |     fn into_u16(&self) -> u16 { 0 }
+LL |     fn into_u16(&self) -> u16 {
    |                 ^^^^^
    |
-   = note: `-D wrong-self-convention` implied by `-D warnings`
+   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 
 error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-  --> $DIR/methods.rs:34:21
+  --> $DIR/methods.rs:74:21
    |
-34 |     fn to_something(self) -> u32 { 0 }
+LL |     fn to_something(self) -> u32 {
    |                     ^^^^
 
 error: methods called `new` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/methods.rs:36:12
+  --> $DIR/methods.rs:78:12
    |
-36 |     fn new(self) {}
+LL |     fn new(self) -> Self {
    |            ^^^^
 
-error: methods called `new` usually return `Self`
-  --> $DIR/methods.rs:36:5
+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:157:13
    |
-36 |     fn new(self) {}
-   |     ^^^^^^^^^^^^^^^
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |                 // Should lint even though this call is on a separate line.
+LL | |                .unwrap_or(0);
+   | |____________________________^
    |
-   = note: `-D new-ret-no-self` implied by `-D warnings`
-
-error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
-   --> $DIR/methods.rs:104:13
-    |
-104 |       let _ = opt.map(|x| x + 1)
-    |  _____________^
-105 | |
-106 | |                .unwrap_or(0); // should lint even though this call is on a separate line
-    | |____________________________^
-    |
-    = note: `-D option-map-unwrap-or` implied by `-D warnings`
-    = note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)`
+   = note: `-D clippy::option-map-unwrap-or` implied by `-D warnings`
+   = note: replace `map(|x| x + 1).unwrap_or(0)` with `map_or(0, |x| x + 1)`
 
 error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
-   --> $DIR/methods.rs:108:13
-    |
-108 |       let _ = opt.map(|x| {
-    |  _____________^
-109 | |                         x + 1
-110 | |                     }
-111 | |               ).unwrap_or(0);
-    | |____________________________^
+  --> $DIR/methods.rs:161:13
+   |
+LL |       let _ = opt.map(|x| {
+   |  _____________^
+LL | |                         x + 1
+LL | |                     }
+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:112:13
-    |
-112 |       let _ = opt.map(|x| x + 1)
-    |  _____________^
-113 | |                .unwrap_or({
-114 | |                     0
-115 | |                 });
-    | |__________________^
+  --> $DIR/methods.rs:165:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |                .unwrap_or({
+LL | |                     0
+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:117:13
-    |
-117 |     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))`
+  --> $DIR/methods.rs:170:13
+   |
+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:119:13
-    |
-119 |       let _ = opt.map(|x| {
-    |  _____________^
-120 | |         Some(x + 1)
-121 | |     }
-122 | |     ).unwrap_or(None);
-    | |_____________________^
+  --> $DIR/methods.rs:172:13
+   |
+LL |       let _ = opt.map(|x| {
+   |  _____________^
+LL | |         Some(x + 1)
+LL | |     }
+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:123:13
-    |
-123 |       let _ = opt
-    |  _____________^
-124 | |         .map(|x| Some(x + 1))
-125 | |         .unwrap_or(None);
-    | |________________________^
-    |
-    = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))`
+  --> $DIR/methods.rs:176:13
+   |
+LL |       let _ = opt
+   |  _____________^
+LL | |         .map(|x| Some(x + 1))
+LL | |         .unwrap_or(None);
+   | |________________________^
+   |
+   = note: replace `map(|x| Some(x + 1)).unwrap_or(None)` with `and_then(|x| Some(x + 1))`
 
-error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
-   --> $DIR/methods.rs:131:13
-    |
-131 |       let _ = opt.map(|x| x + 1)
-    |  _____________^
-132 | |
-133 | |                .unwrap_or_else(|| 0); // should lint even though this call is on a separate line
-    | |____________________________________^
-    |
-    = note: `-D option-map-unwrap-or-else` implied by `-D warnings`
-    = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)`
+error: called `map(f).unwrap_or(a)` on an Option value. This can be done more directly by calling `map_or(a, f)` instead
+  --> $DIR/methods.rs:187:13
+   |
+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:135:13
-    |
-135 |       let _ = opt.map(|x| {
-    |  _____________^
-136 | |                         x + 1
-137 | |                     }
-138 | |               ).unwrap_or_else(|| 0);
-    | |____________________________________^
+  --> $DIR/methods.rs:191:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |                 // Should lint even though this call is on a separate line.
+LL | |                .unwrap_or_else(|| 0);
+   | |____________________________________^
+   |
+   = note: `-D clippy::option-map-unwrap-or-else` implied by `-D warnings`
+   = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)`
 
 error: called `map(f).unwrap_or_else(g)` on an Option value. This can be done more directly by calling `map_or_else(g, f)` instead
-   --> $DIR/methods.rs:139:13
-    |
-139 |       let _ = opt.map(|x| x + 1)
-    |  _____________^
-140 | |                .unwrap_or_else(||
-141 | |                     0
-142 | |                 );
-    | |_________________^
-
-error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead
-   --> $DIR/methods.rs:148:13
-    |
-148 |     let _ = opt.map_or(None, |x| Some(x + 1));
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using and_then instead: `opt.and_then(|x| Some(x + 1))`
-    |
-    = note: `-D option-map-or-none` implied by `-D warnings`
-
-error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead
-   --> $DIR/methods.rs:150:13
-    |
-150 |       let _ = opt.map_or(None, |x| {
-    |  _____________^
-151 | |                         Some(x + 1)
-152 | |                        }
-153 | |                 );
-    | |_________________^
-help: try using and_then instead
-    |
-150 |     let _ = opt.and_then(|x| {
-151 |                         Some(x + 1)
-152 |                        });
-    |
-
-error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead
-   --> $DIR/methods.rs:163:13
-    |
-163 |       let _ = res.map(|x| x + 1)
-    |  _____________^
-164 | |
-165 | |                .unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
-    | |_____________________________________^
-    |
-    = note: `-D result-map-unwrap-or-else` implied by `-D warnings`
-    = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)`
-
-error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead
-   --> $DIR/methods.rs:167:13
-    |
-167 |       let _ = res.map(|x| {
-    |  _____________^
-168 | |                         x + 1
-169 | |                     }
-170 | |               ).unwrap_or_else(|e| 0);
-    | |_____________________________________^
+  --> $DIR/methods.rs:195:13
+   |
+LL |       let _ = opt.map(|x| {
+   |  _____________^
+LL | |                         x + 1
+LL | |                     }
+LL | |               ).unwrap_or_else(|| 0);
+   | |____________________________________^
 
-error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead
-   --> $DIR/methods.rs:171:13
-    |
-171 |       let _ = res.map(|x| x + 1)
-    |  _____________^
-172 | |                .unwrap_or_else(|e|
-173 | |                     0
-174 | |                 );
-    | |_________________^
+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:199:13
+   |
+LL |       let _ = opt.map(|x| x + 1)
+   |  _____________^
+LL | |                .unwrap_or_else(||
+LL | |                     0
+LL | |                 );
+   | |_________________^
 
 error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
-   --> $DIR/methods.rs:234:13
-    |
-234 |     let _ = v.iter().filter(|&x| *x < 0).next();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: `-D filter-next` implied by `-D warnings`
-    = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
+  --> $DIR/methods.rs:214:13
+   |
+LL |     let _ = v.iter().filter(|&x| *x < 0).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::filter-next` implied by `-D warnings`
+   = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)`
 
 error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
-   --> $DIR/methods.rs:237:13
-    |
-237 |       let _ = v.iter().filter(|&x| {
-    |  _____________^
-238 | |                                 *x < 0
-239 | |                             }
-240 | |                    ).next();
-    | |___________________________^
+  --> $DIR/methods.rs:217:13
+   |
+LL |       let _ = v.iter().filter(|&x| {
+   |  _____________^
+LL | |                                 *x < 0
+LL | |                             }
+LL | |                    ).next();
+   | |___________________________^
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:252:13
-    |
-252 |     let _ = v.iter().find(|&x| *x < 0).is_some();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: `-D search-is-some` implied by `-D warnings`
-    = note: replace `find(|&x| *x < 0).is_some()` with `any(|&x| *x < 0)`
+  --> $DIR/methods.rs:233:13
+   |
+LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::search-is-some` implied by `-D warnings`
+   = note: replace `find(|&x| *x < 0).is_some()` with `any(|x| *x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:255:13
-    |
-255 |       let _ = v.iter().find(|&x| {
-    |  _____________^
-256 | |                               *x < 0
-257 | |                           }
-258 | |                    ).is_some();
-    | |______________________________^
+  --> $DIR/methods.rs:236:13
+   |
+LL |       let _ = v.iter().find(|&x| {
+   |  _____________^
+LL | |                               *x < 0
+LL | |                           }
+LL | |                    ).is_some();
+   | |______________________________^
 
 error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:261:13
-    |
-261 |     let _ = v.iter().position(|&x| x < 0).is_some();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: replace `position(|&x| x < 0).is_some()` with `any(|&x| x < 0)`
+  --> $DIR/methods.rs:242:13
+   |
+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:264:13
-    |
-264 |       let _ = v.iter().position(|&x| {
-    |  _____________^
-265 | |                                   x < 0
-266 | |                               }
-267 | |                    ).is_some();
-    | |______________________________^
+  --> $DIR/methods.rs:245:13
+   |
+LL |       let _ = v.iter().position(|&x| {
+   |  _____________^
+LL | |                                   x < 0
+LL | |                               }
+LL | |                    ).is_some();
+   | |______________________________^
 
 error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-   --> $DIR/methods.rs:270:13
-    |
-270 |     let _ = v.iter().rposition(|&x| x < 0).is_some();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: replace `rposition(|&x| x < 0).is_some()` with `any(|&x| x < 0)`
+  --> $DIR/methods.rs:251:13
+   |
+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:273:13
-    |
-273 |       let _ = v.iter().rposition(|&x| {
-    |  _____________^
-274 | |                                    x < 0
-275 | |                                }
-276 | |                    ).is_some();
-    | |______________________________^
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:308:22
-    |
-308 |     with_constructor.unwrap_or(make());
-    |                      ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
-    |
-    = note: `-D or-fun-call` implied by `-D warnings`
-
-error: use of `unwrap_or` followed by a call to `new`
-   --> $DIR/methods.rs:311:5
-    |
-311 |     with_new.unwrap_or(Vec::new());
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:314:21
-    |
-314 |     with_const_args.unwrap_or(Vec::with_capacity(12));
-    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:317:14
-    |
-317 |     with_err.unwrap_or(make());
-    |              ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:320:19
-    |
-320 |     with_err_args.unwrap_or(Vec::with_capacity(12));
-    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
-
-error: use of `unwrap_or` followed by a call to `default`
-   --> $DIR/methods.rs:323:5
-    |
-323 |     with_default_trait.unwrap_or(Default::default());
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `default`
-   --> $DIR/methods.rs:326:5
-    |
-326 |     with_default_type.unwrap_or(u64::default());
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:329:14
-    |
-329 |     with_vec.unwrap_or(vec![]);
-    |              ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| < [ _ ] > :: into_vec ( box [ $ ( $ x ) , * ] ))`
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:334:21
-    |
-334 |     without_default.unwrap_or(Foo::new());
-    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
-
-error: use of `or_insert` followed by a function call
-   --> $DIR/methods.rs:337:19
-    |
-337 |     map.entry(42).or_insert(String::new());
-    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
-
-error: use of `or_insert` followed by a function call
-   --> $DIR/methods.rs:340:21
-    |
-340 |     btree.entry(42).or_insert(String::new());
-    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
-
-error: use of `unwrap_or` followed by a function call
-   --> $DIR/methods.rs:343:21
-    |
-343 |     let _ = stringy.unwrap_or("".to_owned());
-    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
-
-error: use of `expect` followed by a function call
-   --> $DIR/methods.rs:366:26
-    |
-366 |     with_none_and_format.expect(&format!("Error {}: fake error", error_code));
-    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
-    |
-    = note: `-D expect-fun-call` implied by `-D warnings`
-
-error: use of `expect` followed by a function call
-   --> $DIR/methods.rs:369:26
-    |
-369 |     with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
-    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!(format!("Error {}: fake error", error_code).as_str()))`
-
-error: use of `expect` followed by a function call
-   --> $DIR/methods.rs:379:25
-    |
-379 |     with_err_and_format.expect(&format!("Error {}: fake error", error_code));
-    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
-
-error: use of `expect` followed by a function call
-   --> $DIR/methods.rs:382:25
-    |
-382 |     with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
-    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!(format!("Error {}: fake error", error_code).as_str()))`
-
-error: called `.iter().nth()` on a Vec. Calling `.get()` is both faster and more readable
-   --> $DIR/methods.rs:402:23
-    |
-402 |         let bad_vec = some_vec.iter().nth(3);
-    |                       ^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: `-D iter-nth` implied by `-D warnings`
-
-error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable
-   --> $DIR/methods.rs:403:26
-    |
-403 |         let bad_slice = &some_vec[..].iter().nth(3);
-    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `.iter().nth()` on a slice. Calling `.get()` is both faster and more readable
-   --> $DIR/methods.rs:404:31
-    |
-404 |         let bad_boxed_slice = boxed_slice.iter().nth(3);
-    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `.iter().nth()` on a VecDeque. Calling `.get()` is both faster and more readable
-   --> $DIR/methods.rs:405:29
-    |
-405 |         let bad_vec_deque = some_vec_deque.iter().nth(3);
-    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `.iter_mut().nth()` on a Vec. Calling `.get_mut()` is both faster and more readable
-   --> $DIR/methods.rs:410:23
-    |
-410 |         let bad_vec = some_vec.iter_mut().nth(3);
-    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `.iter_mut().nth()` on a slice. Calling `.get_mut()` is both faster and more readable
-   --> $DIR/methods.rs:413:26
-    |
-413 |         let bad_slice = &some_vec[..].iter_mut().nth(3);
-    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both faster and more readable
-   --> $DIR/methods.rs:416:29
-    |
-416 |         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
-    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-   --> $DIR/methods.rs:428:13
-    |
-428 |     let _ = some_vec.iter().skip(42).next();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: `-D iter-skip-next` implied by `-D warnings`
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-   --> $DIR/methods.rs:429:13
-    |
-429 |     let _ = some_vec.iter().cycle().skip(42).next();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-   --> $DIR/methods.rs:430:13
-    |
-430 |     let _ = (1..10).skip(10).next();
-    |             ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-   --> $DIR/methods.rs:431:14
-    |
-431 |     let _ = &some_vec[..].iter().skip(3).next();
-    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/methods.rs:254:13
+   |
+LL |       let _ = v.iter().rposition(|&x| {
+   |  _____________^
+LL | |                                    x < 0
+LL | |                                }
+LL | |                    ).is_some();
+   | |______________________________^
 
 error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message
-   --> $DIR/methods.rs:440:13
-    |
-440 |     let _ = opt.unwrap();
-    |             ^^^^^^^^^^^^
-    |
-    = note: `-D option-unwrap-used` implied by `-D warnings`
+  --> $DIR/methods.rs:269:13
+   |
+LL |     let _ = opt.unwrap();
+   |             ^^^^^^^^^^^^
+   |
+   = note: `-D clippy::option-unwrap-used` implied by `-D warnings`
 
-error: aborting due to 55 previous errors
+error: aborting due to 23 previous errors
 
index 9b29f73b2ac2139c885b7214d55125a842f3f8bf..8307d4b3019f7cf077fc673c34bc7481da55c3ae 100644 (file)
@@ -1,13 +1,10 @@
+#![warn(clippy::all)]
 
-
-
-#![warn(clippy)]
-
-use std::cmp::{min, max};
-use std::cmp::min as my_min;
 use std::cmp::max as my_max;
+use std::cmp::min as my_min;
+use std::cmp::{max, min};
 
-const LARGE : usize = 3;
+const LARGE: usize = 3;
 
 fn main() {
     let x;
index b8ea183fcc942e40e07a1f6221c44f1112cf66b9..6d68d39e8d36fd03c21e5396ce78554bafaa978d 100644 (file)
@@ -1,45 +1,45 @@
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:15:5
+  --> $DIR/min_max.rs:12:5
    |
-15 |     min(1, max(3, x));
+LL |     min(1, max(3, x));
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D min-max` implied by `-D warnings`
+   = note: `-D clippy::min-max` implied by `-D warnings`
 
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:16:5
+  --> $DIR/min_max.rs:13:5
    |
-16 |     min(max(3, x), 1);
+LL |     min(max(3, x), 1);
    |     ^^^^^^^^^^^^^^^^^
 
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:17:5
+  --> $DIR/min_max.rs:14:5
    |
-17 |     max(min(x, 1), 3);
+LL |     max(min(x, 1), 3);
    |     ^^^^^^^^^^^^^^^^^
 
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:18:5
+  --> $DIR/min_max.rs:15:5
    |
-18 |     max(3, min(x, 1));
+LL |     max(3, min(x, 1));
    |     ^^^^^^^^^^^^^^^^^
 
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:20:5
+  --> $DIR/min_max.rs:17:5
    |
-20 |     my_max(3, my_min(x, 1));
+LL |     my_max(3, my_min(x, 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:32:5
+  --> $DIR/min_max.rs:29:5
    |
-32 |     min("Apple", max("Zoo", s));
+LL |     min("Apple", max("Zoo", s));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this min/max combination leads to constant result
-  --> $DIR/min_max.rs:33:5
+  --> $DIR/min_max.rs:30:5
    |
-33 |     max(min(s, "Apple"), "Zoo");
+LL |     max(min(s, "Apple"), "Zoo");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/missing-doc-crate-missing.rs b/tests/ui/missing-doc-crate-missing.rs
new file mode 100644 (file)
index 0000000..51fd57d
--- /dev/null
@@ -0,0 +1,3 @@
+#![warn(clippy::missing_docs_in_private_items)]
+
+fn main() {}
diff --git a/tests/ui/missing-doc-crate-missing.stderr b/tests/ui/missing-doc-crate-missing.stderr
new file mode 100644 (file)
index 0000000..da46f98
--- /dev/null
@@ -0,0 +1,12 @@
+error: missing documentation for crate
+  --> $DIR/missing-doc-crate-missing.rs:1:1
+   |
+LL | / #![warn(clippy::missing_docs_in_private_items)]
+LL | |
+LL | | fn main() {}
+   | |____________^
+   |
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/missing-doc-crate.rs b/tests/ui/missing-doc-crate.rs
new file mode 100644 (file)
index 0000000..04711f8
--- /dev/null
@@ -0,0 +1,5 @@
+#![warn(clippy::missing_docs_in_private_items)]
+#![feature(external_doc)]
+#![doc(include = "../../README.md")]
+
+fn main() {}
diff --git a/tests/ui/missing-doc-crate.stderr b/tests/ui/missing-doc-crate.stderr
new file mode 100644 (file)
index 0000000..e69de29
index cbd6439d47e8a5e41048f3a89e8a8324bd9148cb..e65bce8e783fe6d8aedd02b8f1fc6457b61cdcf6 100644 (file)
@@ -1,27 +1,11 @@
-/* This file incorporates work covered by the following copyright and
- * permission notice:
- *   Copyright 2013 The Rust Project Developers. See the COPYRIGHT
- *   file at the top-level directory of this distribution and at
- *   http://rust-lang.org/COPYRIGHT.
- *
- *   Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
- *   http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
- *   <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
- *   option. This file may not be copied, modified, or distributed
- *   except according to those terms.
- */
-
-
-
-#![warn(missing_docs_in_private_items)]
-
+#![warn(clippy::missing_docs_in_private_items)]
 // When denying at the crate level, be sure to not get random warnings from the
 // injected intrinsics by the compiler.
 #![allow(dead_code)]
-#![feature(associated_type_defaults)]
+#![feature(associated_type_defaults, global_asm)]
 
 //! Some garbage docs for the crate here
-#![doc="More garbage"]
+#![doc = "More garbage"]
 
 type Typedef = String;
 pub type PubTypedef = String;
@@ -36,7 +20,7 @@ pub struct PubFoo {
     b: isize,
 }
 
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 pub struct PubFoo2 {
     pub a: isize,
     pub c: isize,
@@ -49,7 +33,8 @@ pub mod pub_module_no_dox {}
 pub fn foo() {}
 pub fn foo2() {}
 fn foo3() {}
-#[allow(missing_docs_in_private_items)] pub fn foo4() {}
+#[allow(clippy::missing_docs_in_private_items)]
+pub fn foo4() {}
 
 /// dox
 pub trait A {
@@ -59,7 +44,7 @@ pub trait A {
     fn foo_with_impl(&self) {}
 }
 
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 trait B {
     fn foo(&self);
     fn foo_with_impl(&self) {}
@@ -70,9 +55,9 @@ pub trait C {
     fn foo_with_impl(&self) {}
 }
 
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 pub trait D {
-    fn dummy(&self) { }
+    fn dummy(&self) {}
 }
 
 /// dox
@@ -98,10 +83,11 @@ pub fn foo() {}
     /// dox
     pub fn foo1() {}
     fn foo2() {}
-    #[allow(missing_docs_in_private_items)] pub fn foo3() {}
+    #[allow(clippy::missing_docs_in_private_items)]
+    pub fn foo3() {}
 }
 
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 trait F {
     fn a();
     fn b(&self);
@@ -124,17 +110,12 @@ pub fn baz() {}
 }
 
 enum Baz {
-    BazA {
-        a: isize,
-        b: isize
-    },
-    BarB
+    BazA { a: isize, b: isize },
+    BarB,
 }
 
 pub enum PubBaz {
-    PubBazA {
-        a: isize,
-    },
+    PubBazA { a: isize },
 }
 
 /// dox
@@ -146,37 +127,32 @@ pub enum PubBaz2 {
     },
 }
 
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 pub enum PubBaz3 {
-    PubBaz3A {
-        b: isize
-    },
+    PubBaz3A { b: isize },
 }
 
 #[doc(hidden)]
 pub fn baz() {}
 
-
 const FOO: u32 = 0;
 /// dox
 pub const FOO1: u32 = 0;
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 pub const FOO2: u32 = 0;
 #[doc(hidden)]
 pub const FOO3: u32 = 0;
 pub const FOO4: u32 = 0;
 
-
 static BAR: u32 = 0;
 /// dox
 pub static BAR1: u32 = 0;
-#[allow(missing_docs_in_private_items)]
+#[allow(clippy::missing_docs_in_private_items)]
 pub static BAR2: u32 = 0;
 #[doc(hidden)]
 pub static BAR3: u32 = 0;
 pub static BAR4: u32 = 0;
 
-
 mod internal_impl {
     /// dox
     pub fn documented() {}
@@ -194,9 +170,12 @@ fn also_undocumented2() {}
 /// dox
 pub mod public_interface {
     pub use internal_impl::documented as foo;
+    pub use internal_impl::globbed::*;
     pub use internal_impl::undocumented1 as bar;
     pub use internal_impl::{documented, undocumented2};
-    pub use internal_impl::globbed::*;
 }
 
 fn main() {}
+
+// Ensure global asm doesn't require documentation.
+global_asm! { "" }
index 54834f9021c9c9904c95ebaf69edb65abf553039..a3ae62217a2712a2b62bd15d958489f59c1d62df 100644 (file)
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:26:1
+  --> $DIR/missing-doc.rs:10:1
    |
-26 | type Typedef = String;
+LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D missing-docs-in-private-items` implied by `-D warnings`
+   = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:27:1
+  --> $DIR/missing-doc.rs:11:1
    |
-27 | pub type PubTypedef = String;
+LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct
-  --> $DIR/missing-doc.rs:29:1
+  --> $DIR/missing-doc.rs:13:1
    |
-29 | / struct Foo {
-30 | |     a: isize,
-31 | |     b: isize,
-32 | | }
+LL | / struct Foo {
+LL | |     a: isize,
+LL | |     b: isize,
+LL | | }
    | |_^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:30:5
+  --> $DIR/missing-doc.rs:14:5
    |
-30 |     a: isize,
+LL |     a: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:31:5
+  --> $DIR/missing-doc.rs:15:5
    |
-31 |     b: isize,
+LL |     b: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a struct
-  --> $DIR/missing-doc.rs:34:1
+  --> $DIR/missing-doc.rs:18:1
    |
-34 | / pub struct PubFoo {
-35 | |     pub a: isize,
-36 | |     b: isize,
-37 | | }
+LL | / pub struct PubFoo {
+LL | |     pub a: isize,
+LL | |     b: isize,
+LL | | }
    | |_^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:35:5
+  --> $DIR/missing-doc.rs:19:5
    |
-35 |     pub a: isize,
+LL |     pub a: isize,
    |     ^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:36:5
+  --> $DIR/missing-doc.rs:20:5
    |
-36 |     b: isize,
+LL |     b: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:45:1
+  --> $DIR/missing-doc.rs:29:1
    |
-45 | mod module_no_dox {}
+LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:46:1
+  --> $DIR/missing-doc.rs:30:1
    |
-46 | pub mod pub_module_no_dox {}
+LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:50:1
+  --> $DIR/missing-doc.rs:34:1
    |
-50 | pub fn foo2() {}
+LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:51:1
+  --> $DIR/missing-doc.rs:35:1
    |
-51 | fn foo3() {}
+LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for a trait
-  --> $DIR/missing-doc.rs:68:1
+  --> $DIR/missing-doc.rs:53:1
    |
-68 | / pub trait C {
-69 | |     fn foo(&self);
-70 | |     fn foo_with_impl(&self) {}
-71 | | }
+LL | / pub trait C {
+LL | |     fn foo(&self);
+LL | |     fn foo_with_impl(&self) {}
+LL | | }
    | |_^
 
 error: missing documentation for a trait method
-  --> $DIR/missing-doc.rs:69:5
+  --> $DIR/missing-doc.rs:54:5
    |
-69 |     fn foo(&self);
+LL |     fn foo(&self);
    |     ^^^^^^^^^^^^^^
 
 error: missing documentation for a trait method
-  --> $DIR/missing-doc.rs:70:5
+  --> $DIR/missing-doc.rs:55:5
    |
-70 |     fn foo_with_impl(&self) {}
+LL |     fn foo_with_impl(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/missing-doc.rs:80:5
+  --> $DIR/missing-doc.rs:65:5
    |
-80 |     type AssociatedType;
+LL |     type AssociatedType;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/missing-doc.rs:81:5
+  --> $DIR/missing-doc.rs:66:5
    |
-81 |     type AssociatedTypeDef = Self;
+LL |     type AssociatedTypeDef = Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a method
-  --> $DIR/missing-doc.rs:92:5
+  --> $DIR/missing-doc.rs:77:5
    |
-92 |     pub fn foo() {}
+LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for a method
-  --> $DIR/missing-doc.rs:93:5
+  --> $DIR/missing-doc.rs:78:5
    |
-93 |     fn bar() {}
+LL |     fn bar() {}
    |     ^^^^^^^^^^^
 
 error: missing documentation for a method
-  --> $DIR/missing-doc.rs:97:5
+  --> $DIR/missing-doc.rs:82:5
    |
-97 |     pub fn foo() {}
+LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for a method
-   --> $DIR/missing-doc.rs:100:5
-    |
-100 |     fn foo2() {}
-    |     ^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:85:5
+   |
+LL |     fn foo2() {}
+   |     ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-   --> $DIR/missing-doc.rs:126:1
-    |
-126 | / enum Baz {
-127 | |     BazA {
-128 | |         a: isize,
-129 | |         b: isize
-130 | |     },
-131 | |     BarB
-132 | | }
-    | |_^
+  --> $DIR/missing-doc.rs:112:1
+   |
+LL | / enum Baz {
+LL | |     BazA { a: isize, b: isize },
+LL | |     BarB,
+LL | | }
+   | |_^
 
 error: missing documentation for a variant
-   --> $DIR/missing-doc.rs:127:5
-    |
-127 | /     BazA {
-128 | |         a: isize,
-129 | |         b: isize
-130 | |     },
-    | |_____^
+  --> $DIR/missing-doc.rs:113:5
+   |
+LL |     BazA { a: isize, b: isize },
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-   --> $DIR/missing-doc.rs:128:9
-    |
-128 |         a: isize,
-    |         ^^^^^^^^
+  --> $DIR/missing-doc.rs:113:12
+   |
+LL |     BazA { a: isize, b: isize },
+   |            ^^^^^^^^
 
 error: missing documentation for a struct field
-   --> $DIR/missing-doc.rs:129:9
-    |
-129 |         b: isize
-    |         ^^^^^^^^
+  --> $DIR/missing-doc.rs:113:22
+   |
+LL |     BazA { a: isize, b: isize },
+   |                      ^^^^^^^^
 
 error: missing documentation for a variant
-   --> $DIR/missing-doc.rs:131:5
-    |
-131 |     BarB
-    |     ^^^^
+  --> $DIR/missing-doc.rs:114:5
+   |
+LL |     BarB,
+   |     ^^^^
 
 error: missing documentation for an enum
-   --> $DIR/missing-doc.rs:134:1
-    |
-134 | / pub enum PubBaz {
-135 | |     PubBazA {
-136 | |         a: isize,
-137 | |     },
-138 | | }
-    | |_^
+  --> $DIR/missing-doc.rs:117:1
+   |
+LL | / pub enum PubBaz {
+LL | |     PubBazA { a: isize },
+LL | | }
+   | |_^
 
 error: missing documentation for a variant
-   --> $DIR/missing-doc.rs:135:5
-    |
-135 | /     PubBazA {
-136 | |         a: isize,
-137 | |     },
-    | |_____^
+  --> $DIR/missing-doc.rs:118:5
+   |
+LL |     PubBazA { a: isize },
+   |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-   --> $DIR/missing-doc.rs:136:9
-    |
-136 |         a: isize,
-    |         ^^^^^^^^
+  --> $DIR/missing-doc.rs:118:15
+   |
+LL |     PubBazA { a: isize },
+   |               ^^^^^^^^
 
 error: missing documentation for a constant
-   --> $DIR/missing-doc.rs:160:1
-    |
-160 | const FOO: u32 = 0;
-    | ^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:138:1
+   |
+LL | const FOO: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a constant
-   --> $DIR/missing-doc.rs:167:1
-    |
-167 | pub const FOO4: u32 = 0;
-    | ^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:145:1
+   |
+LL | pub const FOO4: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-   --> $DIR/missing-doc.rs:170:1
-    |
-170 | static BAR: u32 = 0;
-    | ^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:147:1
+   |
+LL | static BAR: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-   --> $DIR/missing-doc.rs:177:1
-    |
-177 | pub static BAR4: u32 = 0;
-    | ^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:154:1
+   |
+LL | pub static BAR4: u32 = 0;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-   --> $DIR/missing-doc.rs:180:1
-    |
-180 | / mod internal_impl {
-181 | |     /// dox
-182 | |     pub fn documented() {}
-183 | |     pub fn undocumented1() {}
-...   |
-192 | |     }
-193 | | }
-    | |_^
+  --> $DIR/missing-doc.rs:156:1
+   |
+LL | / mod internal_impl {
+LL | |     /// dox
+LL | |     pub fn documented() {}
+LL | |     pub fn undocumented1() {}
+...  |
+LL | |     }
+LL | | }
+   | |_^
 
 error: missing documentation for a function
-   --> $DIR/missing-doc.rs:183:5
-    |
-183 |     pub fn undocumented1() {}
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:159:5
+   |
+LL |     pub fn undocumented1() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-   --> $DIR/missing-doc.rs:184:5
-    |
-184 |     pub fn undocumented2() {}
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:160:5
+   |
+LL |     pub fn undocumented2() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-   --> $DIR/missing-doc.rs:185:5
-    |
-185 |     fn undocumented3() {}
-    |     ^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:161:5
+   |
+LL |     fn undocumented3() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-   --> $DIR/missing-doc.rs:190:9
-    |
-190 |         pub fn also_undocumented1() {}
-    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:166:9
+   |
+LL |         pub fn also_undocumented1() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-   --> $DIR/missing-doc.rs:191:9
-    |
-191 |         fn also_undocumented2() {}
-    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/missing-doc.rs:167:9
+   |
+LL |         fn also_undocumented2() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 39 previous errors
 
diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs
new file mode 100644 (file)
index 0000000..115cc95
--- /dev/null
@@ -0,0 +1,70 @@
+//! False-positive tests to ensure we don't suggest `const` for things where it would cause a
+//! compilation error.
+//! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
+
+#![warn(clippy::missing_const_for_fn)]
+#![feature(start)]
+
+struct Game;
+
+// This should not be linted because it's already const
+const fn already_const() -> i32 {
+    32
+}
+
+impl Game {
+    // This should not be linted because it's already const
+    pub const fn already_const() -> i32 {
+        32
+    }
+}
+
+// Allowing on this function, because it would lint, which we don't want in this case.
+#[allow(clippy::missing_const_for_fn)]
+fn random() -> u32 {
+    42
+}
+
+// We should not suggest to make this function `const` because `random()` is non-const
+fn random_caller() -> u32 {
+    random()
+}
+
+static Y: u32 = 0;
+
+// We should not suggest to make this function `const` because const functions are not allowed to
+// refer to a static variable
+fn get_y() -> u32 {
+    Y
+    //~^ ERROR E0013
+}
+
+// Don't lint entrypoint functions
+#[start]
+fn init(num: isize, something: *const *const u8) -> isize {
+    1
+}
+
+trait Foo {
+    // This should not be suggested to be made const
+    // (rustc doesn't allow const trait methods)
+    fn f() -> u32;
+
+    // This should not be suggested to be made const either
+    fn g() -> u32 {
+        33
+    }
+}
+
+// Don't lint in external macros (derive)
+#[derive(PartialEq, Eq)]
+struct Point(isize, isize);
+
+impl std::ops::Add for Point {
+    type Output = Self;
+
+    // Don't lint in trait impls of derived methods
+    fn add(self, other: Self) -> Self {
+        Point(self.0 + other.0, self.1 + other.1)
+    }
+}
diff --git a/tests/ui/missing_const_for_fn/cant_be_const.stderr b/tests/ui/missing_const_for_fn/cant_be_const.stderr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs
new file mode 100644 (file)
index 0000000..139e64d
--- /dev/null
@@ -0,0 +1,57 @@
+#![warn(clippy::missing_const_for_fn)]
+#![allow(clippy::let_and_return)]
+
+use std::mem::transmute;
+
+struct Game {
+    guess: i32,
+}
+
+impl Game {
+    // Could be const
+    pub fn new() -> Self {
+        Self { guess: 42 }
+    }
+}
+
+// Could be const
+fn one() -> i32 {
+    1
+}
+
+// Could also be const
+fn two() -> i32 {
+    let abc = 2;
+    abc
+}
+
+// FIXME: This is a false positive in the `is_min_const_fn` function.
+// At least until the `const_string_new` feature is stabilzed.
+fn string() -> String {
+    String::new()
+}
+
+// Could be const
+unsafe fn four() -> i32 {
+    4
+}
+
+// Could also be const
+fn generic<T>(t: T) -> T {
+    t
+}
+
+// FIXME: Depends on the `const_transmute` and `const_fn` feature gates.
+// In the future Clippy should be able to suggest this as const, too.
+fn sub(x: u32) -> usize {
+    unsafe { transmute(&x) }
+}
+
+// NOTE: This is currently not yet allowed to be const
+// Once implemented, Clippy should be able to suggest this as const, too.
+fn generic_arr<T: Copy>(t: [T; 1]) -> T {
+    t[0]
+}
+
+// Should not be const
+fn main() {}
diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr
new file mode 100644 (file)
index 0000000..22ea852
--- /dev/null
@@ -0,0 +1,53 @@
+error: this could be a const_fn
+  --> $DIR/could_be_const.rs:12:5
+   |
+LL | /     pub fn new() -> Self {
+LL | |         Self { guess: 42 }
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+
+error: this could be a const_fn
+  --> $DIR/could_be_const.rs:18:1
+   |
+LL | / fn one() -> i32 {
+LL | |     1
+LL | | }
+   | |_^
+
+error: this could be a const_fn
+  --> $DIR/could_be_const.rs:23:1
+   |
+LL | / fn two() -> i32 {
+LL | |     let abc = 2;
+LL | |     abc
+LL | | }
+   | |_^
+
+error: this could be a const_fn
+  --> $DIR/could_be_const.rs:30:1
+   |
+LL | / fn string() -> String {
+LL | |     String::new()
+LL | | }
+   | |_^
+
+error: this could be a const_fn
+  --> $DIR/could_be_const.rs:35:1
+   |
+LL | / unsafe fn four() -> i32 {
+LL | |     4
+LL | | }
+   | |_^
+
+error: this could be a const_fn
+  --> $DIR/could_be_const.rs:40:1
+   |
+LL | / fn generic<T>(t: T) -> T {
+LL | |     t
+LL | | }
+   | |_^
+
+error: aborting due to 6 previous errors
+
index 38f5903307164967f7ef77b5420fc6dd56e472eb..2b2ea6c94c2679c95078c9733643684a98053d41 100644 (file)
@@ -1,16 +1,4 @@
-/* This file incorporates work covered by the following copyright and
- * permission notice:
- *   Copyright 2013 The Rust Project Developers. See the COPYRIGHT
- *   file at the top-level directory of this distribution and at
- *   http://rust-lang.org/COPYRIGHT.
- *
- *   Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
- *   http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
- *   <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
- *   option. This file may not be copied, modified, or distributed
- *   except according to those terms.
- */
-#![warn(missing_inline_in_public_items)]
+#![warn(clippy::missing_inline_in_public_items)]
 #![crate_type = "dylib"]
 // When denying at the crate level, be sure to not get random warnings from the
 // injected intrinsics by the compiler.
@@ -20,7 +8,7 @@
 pub type PubTypedef = String;
 
 struct Foo {} // ok
-pub struct PubFoo { } // ok
+pub struct PubFoo {} // ok
 enum FooE {} // ok
 pub enum PubFooE {} // ok
 
@@ -29,10 +17,12 @@ pub mod pub_module {} // ok
 
 fn foo() {}
 pub fn pub_foo() {} // missing #[inline]
-#[inline] pub fn pub_foo_inline() {} // ok
-#[inline(always)] pub fn pub_foo_inline_always() {} // ok
+#[inline]
+pub fn pub_foo_inline() {} // ok
+#[inline(always)]
+pub fn pub_foo_inline_always() {} // ok
 
-#[allow(missing_inline_in_public_items)]
+#[allow(clippy::missing_inline_in_public_items)]
 pub fn pub_foo_no_inline() {}
 
 trait Bar {
@@ -40,11 +30,11 @@ trait Bar {
     fn Bar_b() {} // ok
 }
 
-
 pub trait PubBar {
     fn PubBar_a(); // ok
     fn PubBar_b() {} // missing #[inline]
-    #[inline] fn PubBar_c() {} // ok
+    #[inline]
+    fn PubBar_c() {} // ok
 }
 
 // none of these need inline because Foo is not exported
index fe343742708d56e0a7368702afd3cf17616b1ff9..40b92b7647bf766065fcba43519b9d0709450e3a 100644 (file)
@@ -1,39 +1,39 @@
 error: missing `#[inline]` for a function
-  --> $DIR/missing_inline.rs:31:1
+  --> $DIR/missing_inline.rs:19:1
    |
-31 | pub fn pub_foo() {} // missing #[inline]
+LL | pub fn pub_foo() {} // missing #[inline]
    | ^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D missing-inline-in-public-items` implied by `-D warnings`
+   = note: `-D clippy::missing-inline-in-public-items` implied by `-D warnings`
 
 error: missing `#[inline]` for a default trait method
-  --> $DIR/missing_inline.rs:46:5
+  --> $DIR/missing_inline.rs:35:5
    |
-46 |     fn PubBar_b() {} // missing #[inline]
+LL |     fn PubBar_b() {} // missing #[inline]
    |     ^^^^^^^^^^^^^^^^
 
 error: missing `#[inline]` for a method
-  --> $DIR/missing_inline.rs:59:5
+  --> $DIR/missing_inline.rs:49:5
    |
-59 |     fn PubBar_a() {} // missing #[inline]
+LL |     fn PubBar_a() {} // missing #[inline]
    |     ^^^^^^^^^^^^^^^^
 
 error: missing `#[inline]` for a method
-  --> $DIR/missing_inline.rs:60:5
+  --> $DIR/missing_inline.rs:50:5
    |
-60 |     fn PubBar_b() {} // missing #[inline]
+LL |     fn PubBar_b() {} // missing #[inline]
    |     ^^^^^^^^^^^^^^^^
 
 error: missing `#[inline]` for a method
-  --> $DIR/missing_inline.rs:61:5
+  --> $DIR/missing_inline.rs:51:5
    |
-61 |     fn PubBar_c() {} // missing #[inline]
+LL |     fn PubBar_c() {} // missing #[inline]
    |     ^^^^^^^^^^^^^^^^
 
 error: missing `#[inline]` for a method
-  --> $DIR/missing_inline.rs:71:5
+  --> $DIR/missing_inline.rs:61:5
    |
-71 |     pub fn PubFooImpl() {} // missing #[inline]
+LL |     pub fn PubFooImpl() {} // missing #[inline]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed
new file mode 100644 (file)
index 0000000..531e44a
--- /dev/null
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+
+fn main() {
+    let fail14 = 2_i32;
+    let fail15 = 4_i64;
+    let fail16 = 7_i8; //
+    let fail17 = 23_i16; //
+    let ok18 = 23_128;
+
+    let fail20 = 2_i8; //
+    let fail21 = 4_i16; //
+
+    let fail24 = 12.34_f64;
+    let fail25 = 1E2_f32;
+    let fail26 = 43E7_f64;
+    let fail27 = 243E17_f32;
+    #[allow(overflowing_literals)]
+    let fail28 = 241_251_235E723_f64;
+    let fail29 = 42_279.911_f32;
+}
diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs
new file mode 100644 (file)
index 0000000..d67c842
--- /dev/null
@@ -0,0 +1,22 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+
+fn main() {
+    let fail14 = 2_32;
+    let fail15 = 4_64;
+    let fail16 = 7_8; //
+    let fail17 = 23_16; //
+    let ok18 = 23_128;
+
+    let fail20 = 2__8; //
+    let fail21 = 4___16; //
+
+    let fail24 = 12.34_64;
+    let fail25 = 1E2_32;
+    let fail26 = 43E7_64;
+    let fail27 = 243E17_32;
+    #[allow(overflowing_literals)]
+    let fail28 = 241251235E723_64;
+    let fail29 = 42279.911_32;
+}
diff --git a/tests/ui/mistyped_literal_suffix.stderr b/tests/ui/mistyped_literal_suffix.stderr
new file mode 100644 (file)
index 0000000..c3fed6a
--- /dev/null
@@ -0,0 +1,76 @@
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:6:18
+   |
+LL |     let fail14 = 2_32;
+   |                  ^^^^ help: did you mean to write: `2_i32`
+   |
+   = note: #[deny(clippy::mistyped_literal_suffixes)] on by default
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:7:18
+   |
+LL |     let fail15 = 4_64;
+   |                  ^^^^ help: did you mean to write: `4_i64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:8:18
+   |
+LL |     let fail16 = 7_8; //
+   |                  ^^^ help: did you mean to write: `7_i8`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:9:18
+   |
+LL |     let fail17 = 23_16; //
+   |                  ^^^^^ help: did you mean to write: `23_i16`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:12:18
+   |
+LL |     let fail20 = 2__8; //
+   |                  ^^^^ help: did you mean to write: `2_i8`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:13:18
+   |
+LL |     let fail21 = 4___16; //
+   |                  ^^^^^^ help: did you mean to write: `4_i16`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:15:18
+   |
+LL |     let fail24 = 12.34_64;
+   |                  ^^^^^^^^ help: did you mean to write: `12.34_f64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:16:18
+   |
+LL |     let fail25 = 1E2_32;
+   |                  ^^^^^^ help: did you mean to write: `1E2_f32`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:17:18
+   |
+LL |     let fail26 = 43E7_64;
+   |                  ^^^^^^^ help: did you mean to write: `43E7_f64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:18:18
+   |
+LL |     let fail27 = 243E17_32;
+   |                  ^^^^^^^^^ help: did you mean to write: `243E17_f32`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:20:18
+   |
+LL |     let fail28 = 241251235E723_64;
+   |                  ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
+
+error: mistyped literal suffix
+  --> $DIR/mistyped_literal_suffix.rs:21:18
+   |
+LL |     let fail29 = 42279.911_32;
+   |                  ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32`
+
+error: aborting due to 12 previous errors
+
index 77bd446c569c45d80621e5e601e4462e68448c9b..a23aba9164a5c2d22cfc20b30ad4251da01b26a7 100644 (file)
@@ -1,6 +1,4 @@
-
-
-#![warn(module_inception)]
+#![warn(clippy::module_inception)]
 
 mod foo {
     mod bar {
@@ -14,11 +12,10 @@ mod bar {}
     }
 }
 
-// No warning. See <https://github.com/rust-lang-nursery/rust-clippy/issues/1220>.
+// No warning. See <https://github.com/rust-lang/rust-clippy/issues/1220>.
 mod bar {
-    #[allow(module_inception)]
-    mod bar {
-    }
+    #[allow(clippy::module_inception)]
+    mod bar {}
 }
 
 fn main() {}
index c9d3319db1b6a1aa6c187298414a3cb22b8faeff..77564dce9eb48fd5a3524f220004d92d2b0f1c08 100644 (file)
@@ -1,19 +1,19 @@
 error: module has the same name as its containing module
--> $DIR/module_inception.rs:7:9
-  |
-7 | /         mod bar {
-8 | |             mod foo {}
-9 | |         }
-  | |_________^
-  |
-  = note: `-D module-inception` implied by `-D warnings`
 --> $DIR/module_inception.rs:5:9
+   |
+LL | /         mod bar {
+LL | |             mod foo {}
+LL | |         }
+   | |_________^
+   |
+   = note: `-D clippy::module-inception` implied by `-D warnings`
 
 error: module has the same name as its containing module
-  --> $DIR/module_inception.rs:12:5
+  --> $DIR/module_inception.rs:10:5
    |
-12 | /     mod foo {
-13 | |         mod bar {}
-14 | |     }
+LL | /     mod foo {
+LL | |         mod bar {}
+LL | |     }
    | |_____^
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/module_name_repetitions.rs b/tests/ui/module_name_repetitions.rs
new file mode 100644 (file)
index 0000000..669bf01
--- /dev/null
@@ -0,0 +1,26 @@
+// compile-flags: --test
+
+#![warn(clippy::module_name_repetitions)]
+#![allow(dead_code)]
+
+mod foo {
+    pub fn foo() {}
+    pub fn foo_bar() {}
+    pub fn bar_foo() {}
+    pub struct FooCake {}
+    pub enum CakeFoo {}
+    pub struct Foo7Bar;
+
+    // Should not warn
+    pub struct Foobar;
+}
+
+#[cfg(test)]
+mod test {
+    #[test]
+    fn it_works() {
+        assert_eq!(2 + 2, 4);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/module_name_repetitions.stderr b/tests/ui/module_name_repetitions.stderr
new file mode 100644 (file)
index 0000000..bdd217a
--- /dev/null
@@ -0,0 +1,34 @@
+error: item name starts with its containing module's name
+  --> $DIR/module_name_repetitions.rs:8:5
+   |
+LL |     pub fn foo_bar() {}
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::module-name-repetitions` implied by `-D warnings`
+
+error: item name ends with its containing module's name
+  --> $DIR/module_name_repetitions.rs:9:5
+   |
+LL |     pub fn bar_foo() {}
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: item name starts with its containing module's name
+  --> $DIR/module_name_repetitions.rs:10:5
+   |
+LL |     pub struct FooCake {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: item name ends with its containing module's name
+  --> $DIR/module_name_repetitions.rs:11:5
+   |
+LL |     pub enum CakeFoo {}
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: item name starts with its containing module's name
+  --> $DIR/module_name_repetitions.rs:12:5
+   |
+LL |     pub struct Foo7Bar;
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
index 847ea1d9ab64fa571656e2c89c69b012b4d18485..81603175ab44038dd70bc2ee2a8112daac15fa1b 100644 (file)
@@ -1,7 +1,5 @@
-
-
-#![warn(modulo_one)]
-#![allow(no_effect, unnecessary_operation)]
+#![warn(clippy::modulo_one)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
 
 fn main() {
     10 % 1;
index ccfca7154e042deaf5c844636f5f5d455d705534..a7feeb56ebc05a0e7fe8c606e542bc0b7851f741 100644 (file)
@@ -1,10 +1,10 @@
 error: any number modulo 1 will be 0
--> $DIR/modulo_one.rs:7:5
-  |
-7 |     10 % 1;
-  |     ^^^^^^
-  |
-  = note: `-D modulo-one` implied by `-D warnings`
 --> $DIR/modulo_one.rs:5:5
+   |
+LL |     10 % 1;
+   |     ^^^^^^
+   |
+   = note: `-D clippy::modulo-one` implied by `-D warnings`
 
 error: aborting due to previous error
 
index 3fc464083c443d1726dc655a6101d8dee3231159..8f9ed7ed6374ae54be266c9c7476a31e65ed273a 100644 (file)
@@ -1,7 +1,5 @@
-
-
-#![allow(unused, trivially_copy_pass_by_ref)]
-#![warn(mut_from_ref)]
+#![allow(unused, clippy::trivially_copy_pass_by_ref)]
+#![warn(clippy::mut_from_ref)]
 
 struct Foo;
 
index a7cbc0b7a096fc00718347eebb8070b1a6835e6e..4787999920bc219fde94225fd530ba3fba2c3253 100644 (file)
@@ -1,62 +1,62 @@
 error: mutable borrow from immutable input(s)
--> $DIR/mut_from_ref.rs:9:39
-  |
-9 |     fn this_wont_hurt_a_bit(&self) -> &mut Foo {
-  |                                       ^^^^^^^^
-  |
-  = note: `-D mut-from-ref` implied by `-D warnings`
 --> $DIR/mut_from_ref.rs:7:39
+   |
+LL |     fn this_wont_hurt_a_bit(&self) -> &mut Foo {
+   |                                       ^^^^^^^^
+   |
+   = note: `-D clippy::mut-from-ref` implied by `-D warnings`
 note: immutable borrow here
--> $DIR/mut_from_ref.rs:9:29
-  |
-9 |     fn this_wont_hurt_a_bit(&self) -> &mut Foo {
-  |                             ^^^^^
 --> $DIR/mut_from_ref.rs:7:29
+   |
+LL |     fn this_wont_hurt_a_bit(&self) -> &mut Foo {
+   |                             ^^^^^
 
 error: mutable borrow from immutable input(s)
-  --> $DIR/mut_from_ref.rs:15:25
+  --> $DIR/mut_from_ref.rs:13:25
    |
-15 |     fn ouch(x: &Foo) -> &mut Foo;
+LL |     fn ouch(x: &Foo) -> &mut Foo;
    |                         ^^^^^^^^
    |
 note: immutable borrow here
-  --> $DIR/mut_from_ref.rs:15:16
+  --> $DIR/mut_from_ref.rs:13:16
    |
-15 |     fn ouch(x: &Foo) -> &mut Foo;
+LL |     fn ouch(x: &Foo) -> &mut Foo;
    |                ^^^^
 
 error: mutable borrow from immutable input(s)
-  --> $DIR/mut_from_ref.rs:24:21
+  --> $DIR/mut_from_ref.rs:22:21
    |
-24 | fn fail(x: &u32) -> &mut u16 {
+LL | fn fail(x: &u32) -> &mut u16 {
    |                     ^^^^^^^^
    |
 note: immutable borrow here
-  --> $DIR/mut_from_ref.rs:24:12
+  --> $DIR/mut_from_ref.rs:22:12
    |
-24 | fn fail(x: &u32) -> &mut u16 {
+LL | fn fail(x: &u32) -> &mut u16 {
    |            ^^^^
 
 error: mutable borrow from immutable input(s)
-  --> $DIR/mut_from_ref.rs:28:50
+  --> $DIR/mut_from_ref.rs:26:50
    |
-28 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
+LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
    |                                                  ^^^^^^^^^^^
    |
 note: immutable borrow here
-  --> $DIR/mut_from_ref.rs:28:25
+  --> $DIR/mut_from_ref.rs:26:25
    |
-28 | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
+LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
    |                         ^^^^^^^
 
 error: mutable borrow from immutable input(s)
-  --> $DIR/mut_from_ref.rs:32:67
+  --> $DIR/mut_from_ref.rs:30:67
    |
-32 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
+LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
    |                                                                   ^^^^^^^^^^^
    |
 note: immutable borrow here
-  --> $DIR/mut_from_ref.rs:32:27
+  --> $DIR/mut_from_ref.rs:30:27
    |
-32 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
+LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
    |                           ^^^^^^^     ^^^^^^^
 
 error: aborting due to 5 previous errors
index 658ae18466f717a39699bd55091a518a3ee20a97..8965cef66deddc899b5e1779a7f8814ebf61849d 100644 (file)
@@ -1,22 +1,18 @@
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
+#![warn(clippy::mut_mut)]
 
-
-
-#![allow(unused, no_effect, unnecessary_operation)]
-#![warn(mut_mut)]
-
-
-
-
-fn fun(x : &mut &mut u32) -> bool {
+fn fun(x: &mut &mut u32) -> bool {
     **x > 0
 }
 
-fn less_fun(x : *mut *mut u32) {
-  let y = x;
+fn less_fun(x: *mut *mut u32) {
+    let y = x;
 }
 
 macro_rules! mut_ptr {
-    ($p:expr) => { &mut $p }
+    ($p:expr) => {
+        &mut $p
+    };
 }
 
 #[allow(unused_mut, unused_variables)]
@@ -27,12 +23,12 @@ fn main() {
     }
 
     if fun(x) {
-        let y : &mut &mut u32 = &mut &mut 2;
+        let y: &mut &mut u32 = &mut &mut 2;
         **y + **x;
     }
 
     if fun(x) {
-        let y : &mut &mut &mut u32 = &mut &mut &mut 2;
+        let y: &mut &mut &mut u32 = &mut &mut &mut 2;
         ***y + **x;
     }
 
index d1f05ea8091fb448256b00b93d7d95367a489ddb..6fa5dbfc29f34d4fd915f6a18cb092b81a6ffad7 100644 (file)
@@ -1,61 +1,61 @@
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:10:12
+  --> $DIR/mut_mut.rs:4:11
    |
-10 | fn fun(x : &mut &mut u32) -> bool {
-   |            ^^^^^^^^^^^^^
+LL | fn fun(x: &mut &mut u32) -> bool {
+   |           ^^^^^^^^^^^^^
    |
-   = note: `-D mut-mut` implied by `-D warnings`
+   = note: `-D clippy::mut-mut` implied by `-D warnings`
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:24:17
+  --> $DIR/mut_mut.rs:20:17
    |
-24 |     let mut x = &mut &mut 1u32;
+LL |     let mut x = &mut &mut 1u32;
    |                 ^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:19:20
+  --> $DIR/mut_mut.rs:14:9
    |
-19 |     ($p:expr) => { &mut $p }
-   |                    ^^^^^^^
+LL |         &mut $p
+   |         ^^^^^^^
 ...
-39 |     let mut z = mut_ptr!(&mut 3u32);
+LL |     let mut z = mut_ptr!(&mut 3u32);
    |                 ------------------- in this macro invocation
 
 error: this expression mutably borrows a mutable reference. Consider reborrowing
-  --> $DIR/mut_mut.rs:26:21
+  --> $DIR/mut_mut.rs:22:21
    |
-26 |         let mut y = &mut x;
+LL |         let mut y = &mut x;
    |                     ^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:30:33
+  --> $DIR/mut_mut.rs:26:32
    |
-30 |         let y : &mut &mut u32 = &mut &mut 2;
-   |                                 ^^^^^^^^^^^
+LL |         let y: &mut &mut u32 = &mut &mut 2;
+   |                                ^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:30:17
+  --> $DIR/mut_mut.rs:26:16
    |
-30 |         let y : &mut &mut u32 = &mut &mut 2;
-   |                 ^^^^^^^^^^^^^
+LL |         let y: &mut &mut u32 = &mut &mut 2;
+   |                ^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:35:38
+  --> $DIR/mut_mut.rs:31:37
    |
-35 |         let y : &mut &mut &mut u32 = &mut &mut &mut 2;
-   |                                      ^^^^^^^^^^^^^^^^
+LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+   |                                     ^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:35:17
+  --> $DIR/mut_mut.rs:31:16
    |
-35 |         let y : &mut &mut &mut u32 = &mut &mut &mut 2;
-   |                 ^^^^^^^^^^^^^^^^^^
+LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+   |                ^^^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> $DIR/mut_mut.rs:35:22
+  --> $DIR/mut_mut.rs:31:21
    |
-35 |         let y : &mut &mut &mut u32 = &mut &mut &mut 2;
-   |                      ^^^^^^^^^^^^^
+LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
+   |                     ^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
index 0e397c7ae8ce639946829bc31df174dfaaf04e3f..1348dd2a3d8bb87a12c6a3af0008c6ae517cb93c 100644 (file)
@@ -1,6 +1,3 @@
-
-
-
 #![allow(unused)]
 
 fn main() {
@@ -15,29 +12,38 @@ fn main() {
 
 fn mut_range_bound_upper() {
     let mut m = 4;
-    for i in 0..m { m = 5; } // warning
+    for i in 0..m {
+        m = 5;
+    } // warning
 }
 
 fn mut_range_bound_lower() {
     let mut m = 4;
-    for i in m..10 { m *= 2; } // warning
+    for i in m..10 {
+        m *= 2;
+    } // warning
 }
 
 fn mut_range_bound_both() {
     let mut m = 4;
     let mut n = 6;
-    for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound)
+    for i in m..n {
+        m = 5;
+        n = 7;
+    } // warning (1 for each mutated bound)
 }
 
 fn mut_range_bound_no_mutation() {
     let mut m = 4;
-    for i in 0..m { continue; } // no warning
+    for i in 0..m {
+        continue;
+    } // no warning
 }
 
 fn mut_borrow_range_bound() {
     let mut m = 4;
     for i in 0..m {
-        let n = &mut m;  // warning
+        let n = &mut m; // warning
         *n += 1;
     }
 }
@@ -45,12 +51,13 @@ fn mut_borrow_range_bound() {
 fn immut_borrow_range_bound() {
     let mut m = 4;
     for i in 0..m {
-        let n = &m;   // should be no warning?
+        let n = &m; // should be no warning?
     }
 }
 
-
 fn immut_range_bound() {
     let m = 4;
-    for i in 0..m { continue; } // no warning
+    for i in 0..m {
+        continue;
+    } // no warning
 }
index d7be7ae1e6fc89c07fa9146791fc8df80a31bcb9..50e94efde5327af395d9c69843bda498827b7bf2 100644 (file)
@@ -1,33 +1,33 @@
 error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
-  --> $DIR/mut_range_bound.rs:18:21
+  --> $DIR/mut_range_bound.rs:16:9
    |
-18 |     for i in 0..m { m = 5; } // warning
-   |                     ^^^^^
+LL |         m = 5;
+   |         ^^^^^
    |
-   = note: `-D mut-range-bound` implied by `-D warnings`
+   = note: `-D clippy::mut-range-bound` implied by `-D warnings`
 
 error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
-  --> $DIR/mut_range_bound.rs:23:22
+  --> $DIR/mut_range_bound.rs:23:9
    |
-23 |     for i in m..10 { m *= 2; } // warning
-   |                      ^^^^^^
+LL |         m *= 2;
+   |         ^^^^^^
 
 error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
-  --> $DIR/mut_range_bound.rs:29:21
+  --> $DIR/mut_range_bound.rs:31:9
    |
-29 |     for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound)
-   |                     ^^^^^
+LL |         m = 5;
+   |         ^^^^^
 
 error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
-  --> $DIR/mut_range_bound.rs:29:28
+  --> $DIR/mut_range_bound.rs:32:9
    |
-29 |     for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound)
-   |                            ^^^^^
+LL |         n = 7;
+   |         ^^^^^
 
 error: attempt to mutate range bound within loop; note that the range of the loop is unchanged
-  --> $DIR/mut_range_bound.rs:40:22
+  --> $DIR/mut_range_bound.rs:46:22
    |
-40 |         let n = &mut m;  // warning
+LL |         let n = &mut m; // warning
    |                      ^
 
 error: aborting due to 5 previous errors
index 34185f6a9c2b94a1dd7ec6c54580d7c3bea5887c..c4379e0ea1c463c6fb0b345b71da3a774b55d627 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![allow(unused_variables, trivially_copy_pass_by_ref)]
+#![allow(unused_variables, clippy::trivially_copy_pass_by_ref)]
 
 fn takes_an_immutable_reference(a: &i32) {}
 fn takes_a_mutable_reference(a: &mut i32) {}
@@ -9,14 +6,12 @@ fn takes_a_mutable_reference(a: &mut i32) {}
 struct MyStruct;
 
 impl MyStruct {
-    fn takes_an_immutable_reference(&self, a: &i32) {
-    }
+    fn takes_an_immutable_reference(&self, a: &i32) {}
 
-    fn takes_a_mutable_reference(&self, a: &mut i32) {
-    }
+    fn takes_a_mutable_reference(&self, a: &mut i32) {}
 }
 
-#[warn(unnecessary_mut_passed)]
+#[warn(clippy::unnecessary_mut_passed)]
 fn main() {
     // Functions
     takes_an_immutable_reference(&mut 42);
@@ -27,7 +22,6 @@ fn main() {
     let my_struct = MyStruct;
     my_struct.takes_an_immutable_reference(&mut 42);
 
-
     // No error
 
     // Functions
index 73df19bf1583986de94f7bb945ccc655cbeef9c9..fa8c82ae0f34022fbc212f7ed8e60622e7bf74d5 100644 (file)
@@ -1,21 +1,21 @@
 error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:22:34
+  --> $DIR/mut_reference.rs:17:34
    |
-22 |     takes_an_immutable_reference(&mut 42);
+LL |     takes_an_immutable_reference(&mut 42);
    |                                  ^^^^^^^
    |
-   = note: `-D unnecessary-mut-passed` implied by `-D warnings`
+   = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings`
 
 error: The function/method `as_ptr` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:24:12
+  --> $DIR/mut_reference.rs:19:12
    |
-24 |     as_ptr(&mut 42);
+LL |     as_ptr(&mut 42);
    |            ^^^^^^^
 
 error: The function/method `takes_an_immutable_reference` doesn't need a mutable reference
-  --> $DIR/mut_reference.rs:28:44
+  --> $DIR/mut_reference.rs:23:44
    |
-28 |     my_struct.takes_an_immutable_reference(&mut 42);
+LL |     my_struct.takes_an_immutable_reference(&mut 42);
    |                                            ^^^^^^^
 
 error: aborting due to 3 previous errors
index 96502738456ccdfa98a2226af9fb445802949bc7..b9d78b7f47924840a10793dbd7b1df58ea759fd9 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(clippy)]
-#![warn(mutex_integer)]
+#![warn(clippy::all)]
+#![warn(clippy::mutex_integer)]
 
 fn main() {
     use std::sync::Mutex;
index 354f9891c1788b0089c05340e24c58c25f523ae3..1b0f5c1571b76b362278b5a5d23d73418467ef8b 100644 (file)
@@ -1,47 +1,47 @@
 error: Consider using an AtomicBool instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
--> $DIR/mutex_atomic.rs:9:5
-  |
-9 |     Mutex::new(true);
-  |     ^^^^^^^^^^^^^^^^
-  |
-  = note: `-D mutex-atomic` implied by `-D warnings`
 --> $DIR/mutex_atomic.rs:6:5
+   |
+LL |     Mutex::new(true);
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::mutex-atomic` implied by `-D warnings`
 
 error: Consider using an AtomicUsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
-  --> $DIR/mutex_atomic.rs:10:5
+  --> $DIR/mutex_atomic.rs:7:5
    |
-10 |     Mutex::new(5usize);
+LL |     Mutex::new(5usize);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: Consider using an AtomicIsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
-  --> $DIR/mutex_atomic.rs:11:5
+  --> $DIR/mutex_atomic.rs:8:5
    |
-11 |     Mutex::new(9isize);
+LL |     Mutex::new(9isize);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: Consider using an AtomicPtr instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
-  --> $DIR/mutex_atomic.rs:13:5
+  --> $DIR/mutex_atomic.rs:10:5
    |
-13 |     Mutex::new(&x as *const u32);
+LL |     Mutex::new(&x as *const u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Consider using an AtomicPtr instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
-  --> $DIR/mutex_atomic.rs:14:5
+  --> $DIR/mutex_atomic.rs:11:5
    |
-14 |     Mutex::new(&mut x as *mut u32);
+LL |     Mutex::new(&mut x as *mut u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Consider using an AtomicUsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
-  --> $DIR/mutex_atomic.rs:15:5
+  --> $DIR/mutex_atomic.rs:12:5
    |
-15 |     Mutex::new(0u32);
+LL |     Mutex::new(0u32);
    |     ^^^^^^^^^^^^^^^^
    |
-   = note: `-D mutex-integer` implied by `-D warnings`
+   = note: `-D clippy::mutex-integer` implied by `-D warnings`
 
 error: Consider using an AtomicIsize instead of a Mutex here. If you just want the locking behaviour and not the internal type, consider using Mutex<()>.
-  --> $DIR/mutex_atomic.rs:16:5
+  --> $DIR/mutex_atomic.rs:13:5
    |
-16 |     Mutex::new(0i32);
+LL |     Mutex::new(0i32);
    |     ^^^^^^^^^^^^^^^^
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/my_lint.rs b/tests/ui/my_lint.rs
new file mode 100644 (file)
index 0000000..c27fd5b
--- /dev/null
@@ -0,0 +1,7 @@
+#[clippy::author]
+#[cfg(any(target_arch = "x86"))]
+pub struct Foo {
+    x: u32,
+}
+
+fn main() {}
index 1213539c827626753bf2cd6730298e3259c1b7f0..75705525790191c551f88cb7591b992aaa26a3e5 100644 (file)
+#![warn(clippy::needless_bool)]
 
+use std::cell::Cell;
 
-#![warn(needless_bool)]
+macro_rules! bool_comparison_trigger {
+    ($($i:ident: $def:expr, $stb:expr );+  $(;)*) => (
 
-#[allow(if_same_then_else)]
+        #[derive(Clone)]
+        pub struct Trigger {
+            $($i: (Cell<bool>, bool, bool)),+
+        }
+
+        #[allow(dead_code)]
+        impl Trigger {
+            pub fn trigger(&self, key: &str) -> bool {
+                $(
+                    if let stringify!($i) = key {
+                        return self.$i.1 && self.$i.2 == $def;
+                    }
+                 )+
+                false
+            }
+        }
+    )
+}
+
+#[allow(clippy::if_same_then_else)]
 fn main() {
     let x = true;
     let y = false;
-    if x { true } else { true };
-    if x { false } else { false };
-    if x { true } else { false };
-    if x { false } else { true };
-    if x && y { false } else { true };
-    if x { x } else { false }; // would also be questionable, but we don't catch this yet
+    if x {
+        true
+    } else {
+        true
+    };
+    if x {
+        false
+    } else {
+        false
+    };
+    if x {
+        true
+    } else {
+        false
+    };
+    if x {
+        false
+    } else {
+        true
+    };
+    if x && y {
+        false
+    } else {
+        true
+    };
+    if x {
+        x
+    } else {
+        false
+    }; // would also be questionable, but we don't catch this yet
     bool_ret(x);
     bool_ret2(x);
     bool_ret3(x);
     bool_ret5(x, x);
     bool_ret4(x);
     bool_ret6(x, x);
+    needless_bool(x);
+    needless_bool2(x);
+    needless_bool3(x);
 }
 
-#[allow(if_same_then_else, needless_return)]
+#[allow(clippy::if_same_then_else, clippy::needless_return)]
 fn bool_ret(x: bool) -> bool {
-    if x { return true } else { return true };
+    if x {
+        return true;
+    } else {
+        return true;
+    };
 }
 
-#[allow(if_same_then_else, needless_return)]
+#[allow(clippy::if_same_then_else, clippy::needless_return)]
 fn bool_ret2(x: bool) -> bool {
-    if x { return false } else { return false };
+    if x {
+        return false;
+    } else {
+        return false;
+    };
 }
 
-#[allow(needless_return)]
+#[allow(clippy::needless_return)]
 fn bool_ret3(x: bool) -> bool {
-    if x { return true } else { return false };
+    if x {
+        return true;
+    } else {
+        return false;
+    };
 }
 
-#[allow(needless_return)]
+#[allow(clippy::needless_return)]
 fn bool_ret5(x: bool, y: bool) -> bool {
-    if x && y { return true } else { return false };
+    if x && y {
+        return true;
+    } else {
+        return false;
+    };
 }
 
-#[allow(needless_return)]
+#[allow(clippy::needless_return)]
 fn bool_ret4(x: bool) -> bool {
-    if x { return false } else { return true };
+    if x {
+        return false;
+    } else {
+        return true;
+    };
 }
 
-#[allow(needless_return)]
+#[allow(clippy::needless_return)]
 fn bool_ret6(x: bool, y: bool) -> bool {
-    if x && y { return false } else { return true };
+    if x && y {
+        return false;
+    } else {
+        return true;
+    };
+}
+
+fn needless_bool(x: bool) {
+    if x == true {};
+}
+
+fn needless_bool2(x: bool) {
+    if x == false {};
+}
+
+fn needless_bool3(x: bool) {
+    bool_comparison_trigger! {
+        test_one:   false, false;
+        test_three: false, false;
+        test_two:   true, true;
+    }
+
+    if x == true {};
+    if x == false {};
+}
+
+fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() {
+    let b = false;
+    let returns_bool = || false;
+
+    let x = if b {
+        true
+    } else if returns_bool() {
+        false
+    } else {
+        true
+    };
 }
index 63e0632445f69429278ad1650900a97e09701bb9..46734ea07a50ac24208b57432a3ed0bfbdb4f686 100644 (file)
 error: this if-then-else expression will always return true
- --> $DIR/needless_bool.rs:9:5
-  |
-9 |     if x { true } else { true };
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D needless-bool` implied by `-D warnings`
+  --> $DIR/needless_bool.rs:31:5
+   |
+LL | /     if x {
+LL | |         true
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^
+   |
+   = note: `-D clippy::needless-bool` implied by `-D warnings`
 
 error: this if-then-else expression will always return false
-  --> $DIR/needless_bool.rs:10:5
+  --> $DIR/needless_bool.rs:36:5
    |
-10 |     if x { false } else { false };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     if x {
+LL | |         false
+LL | |     } else {
+LL | |         false
+LL | |     };
+   | |_____^
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:11:5
+  --> $DIR/needless_bool.rs:41:5
    |
-11 |     if x { true } else { false };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `x`
+LL | /     if x {
+LL | |         true
+LL | |     } else {
+LL | |         false
+LL | |     };
+   | |_____^ help: you can reduce it to: `x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:12:5
+  --> $DIR/needless_bool.rs:46:5
    |
-12 |     if x { false } else { true };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `!x`
+LL | /     if x {
+LL | |         false
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^ help: you can reduce it to: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:13:5
+  --> $DIR/needless_bool.rs:51:5
    |
-13 |     if x && y { false } else { true };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `!(x && y)`
+LL | /     if x && y {
+LL | |         false
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^ help: you can reduce it to: `!(x && y)`
 
 error: this if-then-else expression will always return true
-  --> $DIR/needless_bool.rs:25:5
+  --> $DIR/needless_bool.rs:74:5
    |
-25 |     if x { return true } else { return true };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     if x {
+LL | |         return true;
+LL | |     } else {
+LL | |         return true;
+LL | |     };
+   | |_____^
 
 error: this if-then-else expression will always return false
-  --> $DIR/needless_bool.rs:30:5
+  --> $DIR/needless_bool.rs:83:5
    |
-30 |     if x { return false } else { return false };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     if x {
+LL | |         return false;
+LL | |     } else {
+LL | |         return false;
+LL | |     };
+   | |_____^
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:35:5
+  --> $DIR/needless_bool.rs:92:5
    |
-35 |     if x { return true } else { return false };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return x`
+LL | /     if x {
+LL | |         return true;
+LL | |     } else {
+LL | |         return false;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:40:5
+  --> $DIR/needless_bool.rs:101:5
    |
-40 |     if x && y { return true } else { return false };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return x && y`
+LL | /     if x && y {
+LL | |         return true;
+LL | |     } else {
+LL | |         return false;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return x && y`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:45:5
+  --> $DIR/needless_bool.rs:110:5
+   |
+LL | /     if x {
+LL | |         return false;
+LL | |     } else {
+LL | |         return true;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return !x`
+
+error: this if-then-else expression returns a bool literal
+  --> $DIR/needless_bool.rs:119:5
+   |
+LL | /     if x && y {
+LL | |         return false;
+LL | |     } else {
+LL | |         return true;
+LL | |     };
+   | |_____^ help: you can reduce it to: `return !(x && y)`
+
+error: equality checks against true are unnecessary
+  --> $DIR/needless_bool.rs:127:8
+   |
+LL |     if x == true {};
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+   |
+   = note: `-D clippy::bool-comparison` implied by `-D warnings`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/needless_bool.rs:131:8
+   |
+LL |     if x == false {};
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
+
+error: equality checks against true are unnecessary
+  --> $DIR/needless_bool.rs:141:8
+   |
+LL |     if x == true {};
+   |        ^^^^^^^^^ help: try simplifying it as shown: `x`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/needless_bool.rs:142:8
    |
-45 |     if x { return false } else { return true };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return !x`
+LL |     if x == false {};
+   |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/needless_bool.rs:50:5
+  --> $DIR/needless_bool.rs:151:12
    |
-50 |     if x && y { return false } else { return true };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return !(x && y)`
+LL |       } else if returns_bool() {
+   |  ____________^
+LL | |         false
+LL | |     } else {
+LL | |         true
+LL | |     };
+   | |_____^ help: you can reduce it to: `{ !returns_bool() }`
 
-error: aborting due to 11 previous errors
+error: aborting due to 16 previous errors
 
index b086f0214a9c27ed5104f33941a269916d604d98..a59254625dce62222e287396ae4d1edeabbe7c9e 100644 (file)
@@ -1,11 +1,11 @@
 use std::borrow::Cow;
 
-#[allow(trivially_copy_pass_by_ref)]
+#[allow(clippy::trivially_copy_pass_by_ref)]
 fn x(y: &i32) -> i32 {
     *y
 }
 
-#[warn(clippyneedless_borrow)]
+#[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables)]
 fn main() {
     let a = 5;
@@ -29,7 +29,7 @@ fn main() {
     };
 }
 
-fn f<T:Copy>(y: &T) -> T {
+fn f<T: Copy>(y: &T) -> T {
     *y
 }
 
@@ -42,7 +42,7 @@ trait Trait {}
 impl<'a> Trait for &'a str {}
 
 fn h(_: &Trait) {}
-#[warn(needless_borrow)]
+#[warn(clippy::needless_borrow)]
 #[allow(dead_code)]
 fn issue_1432() {
     let mut v = Vec::<String>::new();
@@ -51,3 +51,10 @@ fn issue_1432() {
 
     let _ = v.iter().filter(|&a| a.is_empty());
 }
+
+#[allow(dead_code)]
+#[warn(clippy::needless_borrow)]
+#[derive(Debug)]
+enum Foo<'a> {
+    Str(&'a str),
+}
index fde38508b32333eec5f9b47629805d4ca6617562..40744160f65919e514dacee45b7f37430f5ab100 100644 (file)
@@ -1,41 +1,41 @@
 error: this expression borrows a reference that is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:13:15
    |
-13 |     let c = x(&&a);
+LL |     let c = x(&&a);
    |               ^^^ help: change this to: `&a`
    |
-   = note: `-D needless-borrow` implied by `-D warnings`
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
 error: this pattern creates a reference to a reference
   --> $DIR/needless_borrow.rs:20:17
    |
-20 |     if let Some(ref cake) = Some(&5) {}
+LL |     if let Some(ref cake) = Some(&5) {}
    |                 ^^^^^^^^ help: change this to: `cake`
 
 error: this expression borrows a reference that is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:27:15
    |
-27 |         46 => &&a,
+LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
 error: this pattern takes a reference on something that is being de-referenced
   --> $DIR/needless_borrow.rs:49:34
    |
-49 |     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+LL |     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
    |                                  ^^^^^^ help: try removing the `&ref` part and just keep: `a`
    |
-   = note: `-D needless-borrowed-reference` implied by `-D warnings`
+   = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings`
 
 error: this pattern takes a reference on something that is being de-referenced
   --> $DIR/needless_borrow.rs:50:30
    |
-50 |     let _ = v.iter().filter(|&ref a| a.is_empty());
+LL |     let _ = v.iter().filter(|&ref a| a.is_empty());
    |                              ^^^^^^ help: try removing the `&ref` part and just keep: `a`
 
 error: this pattern creates a reference to a reference
   --> $DIR/needless_borrow.rs:50:31
    |
-50 |     let _ = v.iter().filter(|&ref a| a.is_empty());
+LL |     let _ = v.iter().filter(|&ref a| a.is_empty());
    |                               ^^^^^ help: change this to: `a`
 
 error: aborting due to 6 previous errors
index 75ffa211180d5f790db27115cee93a4c1931dbb5..c76f4de9b07ab444a29aec630b1e81f4c22fe10d 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#[warn(needless_borrowed_reference)]
+#[warn(clippy::needless_borrowed_reference)]
 #[allow(unused_variables)]
 fn main() {
     let mut v = Vec::<String>::new();
@@ -17,12 +14,12 @@ fn main() {
     let mut var2 = 5;
     let thingy2 = Some(&mut var2);
     if let Some(&mut ref mut v) = thingy2 {
-        //          ^ should *not* be linted
+        //          ^ should **not** be linted
         // v is borrowed as mutable.
         *v = 10;
     }
     if let Some(&mut ref v) = thingy2 {
-        //          ^ should *not* be linted
+        //          ^ should **not** be linted
         // here, v is borrowed as immutable.
         // can't do that:
         //*v = 15;
@@ -40,9 +37,7 @@ enum Animal {
 fn foo(a: &Animal, b: &Animal) {
     match (a, b) {
         (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
-        //                  ^    and   ^ should *not* be linted
-        (&Animal::Dog(ref a), &Animal::Dog(_)) => ()
-        //              ^ should *not* be linted
+        //                  ^    and   ^ should **not** be linted
+        (&Animal::Dog(ref a), &Animal::Dog(_)) => (), //              ^ should **not** be linted
     }
 }
-
index 2a8cf4348d395d692efb34cdfe218bc82b68c211..1b8067f1d6d6b804c70853339faa0f8f69b36c53 100644 (file)
@@ -1,27 +1,27 @@
 error: this pattern takes a reference on something that is being de-referenced
--> $DIR/needless_borrowed_ref.rs:8:34
-  |
-8 |     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
-  |                                  ^^^^^^ help: try removing the `&ref` part and just keep: `a`
-  |
-  = note: `-D needless-borrowed-reference` implied by `-D warnings`
 --> $DIR/needless_borrowed_ref.rs:5:34
+   |
+LL |     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
+   |                                  ^^^^^^ help: try removing the `&ref` part and just keep: `a`
+   |
+   = note: `-D clippy::needless-borrowed-reference` implied by `-D warnings`
 
 error: this pattern takes a reference on something that is being de-referenced
-  --> $DIR/needless_borrowed_ref.rs:13:17
+  --> $DIR/needless_borrowed_ref.rs:10:17
    |
-13 |     if let Some(&ref v) = thingy {
+LL |     if let Some(&ref v) = thingy {
    |                 ^^^^^^ help: try removing the `&ref` part and just keep: `v`
 
 error: this pattern takes a reference on something that is being de-referenced
-  --> $DIR/needless_borrowed_ref.rs:42:27
+  --> $DIR/needless_borrowed_ref.rs:39:27
    |
-42 |         (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
+LL |         (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
    |                           ^^^^^^ help: try removing the `&ref` part and just keep: `k`
 
 error: this pattern takes a reference on something that is being de-referenced
-  --> $DIR/needless_borrowed_ref.rs:42:38
+  --> $DIR/needless_borrowed_ref.rs:39:38
    |
-42 |         (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
+LL |         (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref'
    |                                      ^^^^^^ help: try removing the `&ref` part and just keep: `k`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs
new file mode 100644 (file)
index 0000000..d4815f6
--- /dev/null
@@ -0,0 +1,17 @@
+use std::collections::{BTreeSet, HashMap, HashSet};
+
+#[warn(clippy::needless_collect)]
+#[allow(unused_variables, clippy::iter_cloned_collect)]
+fn main() {
+    let sample = [1; 5];
+    let len = sample.iter().collect::<Vec<_>>().len();
+    if sample.iter().collect::<Vec<_>>().is_empty() {
+        // Empty
+    }
+    sample.iter().cloned().collect::<Vec<_>>().contains(&1);
+    sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+    // Notice the `HashSet`--this should not be linted
+    sample.iter().collect::<HashSet<_>>().len();
+    // Neither should this
+    sample.iter().collect::<BTreeSet<_>>().len();
+}
diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr
new file mode 100644 (file)
index 0000000..684c501
--- /dev/null
@@ -0,0 +1,28 @@
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:7:28
+   |
+LL |     let len = sample.iter().collect::<Vec<_>>().len();
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()`
+   |
+   = note: `-D clippy::needless-collect` implied by `-D warnings`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:8:21
+   |
+LL |     if sample.iter().collect::<Vec<_>>().is_empty() {
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:11:27
+   |
+LL |     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|&x| x == 1)`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:12:34
+   |
+LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()`
+
+error: aborting due to 4 previous errors
+
index 3574b0fb3fdf7515889f445eea256aaf656fba25..5da95647f2c155d4bc7741d731b7561d095411bf 100644 (file)
@@ -1,15 +1,17 @@
-
-
+#![warn(clippy::needless_continue)]
 
 macro_rules! zero {
-    ($x:expr) => ($x == 0);
+    ($x:expr) => {
+        $x == 0
+    };
 }
 
 macro_rules! nonzero {
-    ($x:expr) => (!zero!($x));
+    ($x:expr) => {
+        !zero!($x)
+    };
 }
 
-#[warn(needless_continue)]
 fn main() {
     let mut i = 1;
     while i < 10 {
@@ -17,9 +19,9 @@ fn main() {
 
         if i % 2 == 0 && i % 3 == 0 {
             println!("{}", i);
-            println!("{}", i+1);
+            println!("{}", i + 1);
             if i % 5 == 0 {
-                println!("{}", i+2);
+                println!("{}", i + 2);
             }
             let i = 0;
             println!("bar {} ", i);
@@ -48,3 +50,66 @@ fn main() {
         println!("bleh");
     }
 }
+
+mod issue_2329 {
+    fn condition() -> bool {
+        unimplemented!()
+    }
+    fn update_condition() {}
+
+    // only the outer loop has a label
+    fn foo() {
+        'outer: loop {
+            println!("Entry");
+            while condition() {
+                update_condition();
+                if condition() {
+                    println!("foo-1");
+                } else {
+                    continue 'outer; // should not lint here
+                }
+                println!("foo-2");
+
+                update_condition();
+                if condition() {
+                    continue 'outer; // should not lint here
+                } else {
+                    println!("foo-3");
+                }
+                println!("foo-4");
+            }
+        }
+    }
+
+    // both loops have labels
+    fn bar() {
+        'outer: loop {
+            println!("Entry");
+            'inner: while condition() {
+                update_condition();
+                if condition() {
+                    println!("bar-1");
+                } else {
+                    continue 'outer; // should not lint here
+                }
+                println!("bar-2");
+
+                update_condition();
+                if condition() {
+                    println!("bar-3");
+                } else {
+                    continue 'inner; // should lint here
+                }
+                println!("bar-4");
+
+                update_condition();
+                if condition() {
+                    continue; // should lint here
+                } else {
+                    println!("bar-5");
+                }
+                println!("bar-6");
+            }
+        }
+    }
+}
index 3e0368892a43104f546639381fede9b134080ded..340ae66dae4958e880b0cdf181fa8dbd730d3dc5 100644 (file)
@@ -1,20 +1,20 @@
 error: This else block is redundant.
 
-  --> $DIR/needless_continue.rs:26:16
+  --> $DIR/needless_continue.rs:28:16
    |
-26 |           } else {
+LL |           } else {
    |  ________________^
-27 | |             continue;
-28 | |         }
+LL | |             continue;
+LL | |         }
    | |_________^
    |
-   = note: `-D needless-continue` implied by `-D warnings`
+   = note: `-D clippy::needless-continue` implied by `-D warnings`
    = help: Consider dropping the else clause and merging the code that follows (in the loop) with the if block, like so:
            if i % 2 == 0 && i % 3 == 0 {
            println!("{}", i);
-           println!("{}", i+1);
+           println!("{}", i + 1);
            if i % 5 == 0 {
-               println!("{}", i+2);
+               println!("{}", i + 2);
            }
            let i = 0;
            println!("bar {} ", i);
@@ -37,14 +37,14 @@ error: This else block is redundant.
 
 error: There is no need for an explicit `else` block for this `if` expression
 
-  --> $DIR/needless_continue.rs:41:9
+  --> $DIR/needless_continue.rs:43:9
    |
-41 | /         if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
-42 | |             continue;
-43 | |         } else {
-44 | |             println!("Blabber");
-45 | |             println!("Jabber");
-46 | |         }
+LL | /         if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
+LL | |             continue;
+LL | |         } else {
+LL | |             println!("Blabber");
+LL | |             println!("Jabber");
+LL | |         }
    | |_________^
    |
    = help: Consider dropping the else clause, and moving out the code in the else block, like so:
@@ -55,5 +55,47 @@ error: There is no need for an explicit `else` block for this `if` expression
            println!("Jabber");
            ...
 
-error: aborting due to 2 previous errors
+error: This else block is redundant.
+
+  --> $DIR/needless_continue.rs:100:24
+   |
+LL |                   } else {
+   |  ________________________^
+LL | |                     continue 'inner; // should lint here
+LL | |                 }
+   | |_________________^
+   |
+   = help: Consider dropping the else clause and merging the code that follows (in the loop) with the if block, like so:
+           if condition() {
+           println!("bar-3");
+           // Merged code follows...println!("bar-4");
+           update_condition();
+           if condition() {
+               continue; // should lint here
+           } else {
+               println!("bar-5");
+           }
+           println!("bar-6");
+           }
+           
+
+error: There is no need for an explicit `else` block for this `if` expression
+
+  --> $DIR/needless_continue.rs:106:17
+   |
+LL | /                 if condition() {
+LL | |                     continue; // should lint here
+LL | |                 } else {
+LL | |                     println!("bar-5");
+LL | |                 }
+   | |_________________^
+   |
+   = help: Consider dropping the else clause, and moving out the code in the else block, like so:
+           if condition() {
+               continue;
+           }
+           println!("bar-5");
+           ...
+
+error: aborting due to 4 previous errors
 
index 322df0b879800a0d2eaf351da01326d8f04aeae4..f031dd105c25445568c5a729f2bbf6e28156f2e9 100644 (file)
@@ -1,7 +1,14 @@
-#![warn(needless_pass_by_value)]
-#![allow(dead_code, single_match, if_let_redundant_pattern_matching, many_single_char_names, option_option)]
+#![warn(clippy::needless_pass_by_value)]
+#![allow(
+    dead_code,
+    clippy::single_match,
+    clippy::redundant_pattern_matching,
+    clippy::many_single_char_names,
+    clippy::option_option
+)]
 
 use std::borrow::Borrow;
+use std::collections::HashSet;
 use std::convert::AsRef;
 
 // `v` should be warned
@@ -80,24 +87,19 @@ fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
 
 impl<T: Serialize, U> S<T, U> {
     fn foo(
-        self, // taking `self` by value is always allowed
+        self,
+        // taking `self` by value is always allowed
         s: String,
         t: String,
     ) -> usize {
         s.len() + t.capacity()
     }
 
-    fn bar(
-        _t: T, // Ok, since `&T: Serialize` too
+    fn bar(_t: T, // Ok, since `&T: Serialize` too
     ) {
     }
 
-    fn baz(
-        &self,
-        _u: U,
-        _s: Self,
-    ) {
-    }
+    fn baz(&self, _u: U, _s: Self) {}
 }
 
 trait FalsePositive {
@@ -108,7 +110,9 @@ fn visit_string(s: String) {
 }
 
 // shouldn't warn on extern funcs
-extern "C" fn ext(x: String) -> usize { x.len() }
+extern "C" fn ext(x: String) -> usize {
+    x.len()
+}
 
 // whitelist RangeArgument
 fn range<T: ::std::ops::RangeBounds<usize>>(range: T) {
@@ -132,4 +136,24 @@ fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
     println!("{}", t);
 }
 
-fn main() {}
+// The following 3 lines should not cause an ICE. See #2831
+trait Bar<'a, A> {}
+impl<'b, T> Bar<'b, T> for T {}
+fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {}
+
+// Also this should not cause an ICE. See #2831
+trait Club<'a, A> {}
+impl<T> Club<'static, T> for T {}
+fn more_fun(_item: impl Club<'static, i32>) {}
+
+fn is_sync<T>(_: T)
+where
+    T: Sync,
+{
+}
+
+fn main() {
+    // This should not cause an ICE either
+    // https://github.com/rust-lang/rust-clippy/issues/3144
+    is_sync(HashSet::<usize>::new());
+}
index 2fef0595cb3abe3798c3412da528b3161699955f..ad0e6461c22feb80c92740633789476f30c89c53 100644 (file)
 error: this argument is passed by value, but not consumed in the function body
--> $DIR/needless_pass_by_value.rs:9:23
-  |
-9 | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> {
-  |                       ^^^^^^ help: consider changing the type to: `&[T]`
-  |
-  = note: `-D needless-pass-by-value` implied by `-D warnings`
 --> $DIR/needless_pass_by_value.rs:16:23
+   |
+LL | fn foo<T: Default>(v: Vec<T>, w: Vec<T>, mut x: Vec<T>, y: Vec<T>) -> Vec<T> {
+   |                       ^^^^^^ help: consider changing the type to: `&[T]`
+   |
+   = note: `-D clippy::needless-pass-by-value` implied by `-D warnings`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:23:11
+  --> $DIR/needless_pass_by_value.rs:30:11
    |
-23 | fn bar(x: String, y: Wrapper) {
+LL | fn bar(x: String, y: Wrapper) {
    |           ^^^^^^ help: consider changing the type to: `&str`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:23:22
+  --> $DIR/needless_pass_by_value.rs:30:22
    |
-23 | fn bar(x: String, y: Wrapper) {
+LL | fn bar(x: String, y: Wrapper) {
    |                      ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:29:71
+  --> $DIR/needless_pass_by_value.rs:36:71
    |
-29 | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) {
+LL | fn test_borrow_trait<T: Borrow<str>, U: AsRef<str>, V>(t: T, u: U, v: V) {
    |                                                                       ^ help: consider taking a reference instead: `&V`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:41:18
+  --> $DIR/needless_pass_by_value.rs:48:18
    |
-41 | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) {
+LL | fn test_match(x: Option<Option<String>>, y: Option<Option<String>>) {
    |                  ^^^^^^^^^^^^^^^^^^^^^^
 help: consider taking a reference instead
    |
-41 | fn test_match(x: &Option<Option<String>>, y: Option<Option<String>>) {
-42 |     match *x {
+LL | fn test_match(x: &Option<Option<String>>, y: Option<Option<String>>) {
+LL |     match *x {
    |
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:54:24
+  --> $DIR/needless_pass_by_value.rs:61:24
    |
-54 | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
+LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
    |                        ^^^^^^^ help: consider taking a reference instead: `&Wrapper`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:54:36
+  --> $DIR/needless_pass_by_value.rs:61:36
    |
-54 | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
+LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) {
    |                                    ^^^^^^^
 help: consider taking a reference instead
    |
-54 | fn test_destructure(x: Wrapper, y: &Wrapper, z: Wrapper) {
-55 |     let Wrapper(s) = z; // moved
-56 |     let Wrapper(ref t) = *y; // not moved
-57 |     let Wrapper(_) = *y; // still not moved
+LL | fn test_destructure(x: Wrapper, y: &Wrapper, z: Wrapper) {
+LL |     let Wrapper(s) = z; // moved
+LL |     let Wrapper(ref t) = *y; // not moved
+LL |     let Wrapper(_) = *y; // still not moved
    |
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:70:49
+  --> $DIR/needless_pass_by_value.rs:77:49
    |
-70 | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {}
+LL | fn test_blanket_ref<T: Foo, S: Serialize>(_foo: T, _serializable: S) {}
    |                                                 ^ help: consider taking a reference instead: `&T`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:72:18
+  --> $DIR/needless_pass_by_value.rs:79:18
    |
-72 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                  ^^^^^^ help: consider taking a reference instead: `&String`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:72:29
+  --> $DIR/needless_pass_by_value.rs:79:29
    |
-72 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                             ^^^^^^
 help: consider changing the type to
    |
-72 | fn issue_2114(s: String, t: &str, u: Vec<i32>, v: Vec<i32>) {
+LL | fn issue_2114(s: String, t: &str, u: Vec<i32>, v: Vec<i32>) {
    |                             ^^^^
 help: change `t.clone()` to
    |
-74 |     let _ = t.to_string();
+LL |     let _ = t.to_string();
    |             ^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:72:40
+  --> $DIR/needless_pass_by_value.rs:79:40
    |
-72 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                                        ^^^^^^^^ help: consider taking a reference instead: `&Vec<i32>`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:72:53
+  --> $DIR/needless_pass_by_value.rs:79:53
    |
-72 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: Vec<i32>) {
    |                                                     ^^^^^^^^
 help: consider changing the type to
    |
-72 | fn issue_2114(s: String, t: String, u: Vec<i32>, v: &[i32]) {
+LL | fn issue_2114(s: String, t: String, u: Vec<i32>, v: &[i32]) {
    |                                                     ^^^^^^
 help: change `v.clone()` to
    |
-76 |     let _ = v.to_owned();
+LL |     let _ = v.to_owned();
    |             ^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:84:12
+  --> $DIR/needless_pass_by_value.rs:92:12
    |
-84 |         s: String,
+LL |         s: String,
    |            ^^^^^^ help: consider changing the type to: `&str`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:85:12
+  --> $DIR/needless_pass_by_value.rs:93:12
    |
-85 |         t: String,
+LL |         t: String,
    |            ^^^^^^ help: consider taking a reference instead: `&String`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:97:13
+  --> $DIR/needless_pass_by_value.rs:102:23
    |
-97 |         _u: U,
-   |             ^ help: consider taking a reference instead: `&U`
+LL |     fn baz(&self, _u: U, _s: Self) {}
+   |                       ^ help: consider taking a reference instead: `&U`
 
 error: this argument is passed by value, but not consumed in the function body
-  --> $DIR/needless_pass_by_value.rs:98:13
+  --> $DIR/needless_pass_by_value.rs:102:30
    |
-98 |         _s: Self,
-   |             ^^^^ help: consider taking a reference instead: `&Self`
+LL |     fn baz(&self, _u: U, _s: Self) {}
+   |                              ^^^^ help: consider taking a reference instead: `&Self`
 
 error: this argument is passed by value, but not consumed in the function body
-   --> $DIR/needless_pass_by_value.rs:120:24
-    |
-120 | fn bar_copy(x: u32, y: CopyWrapper) {
-    |                        ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
-    |
+  --> $DIR/needless_pass_by_value.rs:124:24
+   |
+LL | fn bar_copy(x: u32, y: CopyWrapper) {
+   |                        ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
+   |
 help: consider marking this type as Copy
-   --> $DIR/needless_pass_by_value.rs:118:1
-    |
-118 | struct CopyWrapper(u32);
-    | ^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/needless_pass_by_value.rs:122:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-   --> $DIR/needless_pass_by_value.rs:126:29
-    |
-126 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
-    |                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
-    |
+  --> $DIR/needless_pass_by_value.rs:130:29
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+   |                             ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper`
+   |
 help: consider marking this type as Copy
-   --> $DIR/needless_pass_by_value.rs:118:1
-    |
-118 | struct CopyWrapper(u32);
-    | ^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/needless_pass_by_value.rs:122:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this argument is passed by value, but not consumed in the function body
-   --> $DIR/needless_pass_by_value.rs:126:45
-    |
-126 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
-    |                                             ^^^^^^^^^^^
-    |
+  --> $DIR/needless_pass_by_value.rs:130:45
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+   |                                             ^^^^^^^^^^^
+   |
 help: consider marking this type as Copy
-   --> $DIR/needless_pass_by_value.rs:118:1
-    |
-118 | struct CopyWrapper(u32);
-    | ^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/needless_pass_by_value.rs:122:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider taking a reference instead
-    |
-126 | fn test_destructure_copy(x: CopyWrapper, y: &CopyWrapper, z: CopyWrapper) {
-127 |     let CopyWrapper(s) = z; // moved
-128 |     let CopyWrapper(ref t) = *y; // not moved
-129 |     let CopyWrapper(_) = *y; // still not moved
-    |
-
-error: this argument is passed by value, but not consumed in the function body
-   --> $DIR/needless_pass_by_value.rs:126:61
-    |
-126 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
-    |                                                             ^^^^^^^^^^^
-    |
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: &CopyWrapper, z: CopyWrapper) {
+LL |     let CopyWrapper(s) = z; // moved
+LL |     let CopyWrapper(ref t) = *y; // not moved
+LL |     let CopyWrapper(_) = *y; // still not moved
+   |
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:130:61
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) {
+   |                                                             ^^^^^^^^^^^
+   |
 help: consider marking this type as Copy
-   --> $DIR/needless_pass_by_value.rs:118:1
-    |
-118 | struct CopyWrapper(u32);
-    | ^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/needless_pass_by_value.rs:122:1
+   |
+LL | struct CopyWrapper(u32);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider taking a reference instead
-    |
-126 | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: &CopyWrapper) {
-127 |     let CopyWrapper(s) = *z; // moved
-    |
+   |
+LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: &CopyWrapper) {
+LL |     let CopyWrapper(s) = *z; // moved
+   |
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:142:40
+   |
+LL | fn some_fun<'b, S: Bar<'b, ()>>(_item: S) {}
+   |                                        ^ help: consider taking a reference instead: `&S`
+
+error: this argument is passed by value, but not consumed in the function body
+  --> $DIR/needless_pass_by_value.rs:147:20
+   |
+LL | fn more_fun(_item: impl Club<'static, i32>) {}
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>`
 
-error: aborting due to 20 previous errors
+error: aborting due to 22 previous errors
 
index 652e11fee9d6382a6956094a26e21a841b9b2cea..78a0e92d1797976c8a1fcfcdb28aa4d21f90e168 100644 (file)
@@ -1,11 +1,21 @@
-
-
 #![crate_type = "proc-macro"]
-#![warn(needless_pass_by_value)]
+#![warn(clippy::needless_pass_by_value)]
 
 extern crate proc_macro;
 
 use proc_macro::TokenStream;
 
 #[proc_macro_derive(Foo)]
-pub fn foo(_input: TokenStream) -> TokenStream { unimplemented!() }
+pub fn foo(_input: TokenStream) -> TokenStream {
+    unimplemented!()
+}
+
+#[proc_macro]
+pub fn bar(_input: TokenStream) -> TokenStream {
+    unimplemented!()
+}
+
+#[proc_macro_attribute]
+pub fn baz(_args: TokenStream, _input: TokenStream) -> TokenStream {
+    unimplemented!()
+}
index 30613f98f2bce3be8a6b8d8668d235cd74019801..6f1f4c5fb049309a3a7aeecee00aad2608e2d5f8 100644 (file)
@@ -1,9 +1,16 @@
+#![allow(clippy::cognitive_complexity)]
+
+static STATIC: [usize; 4] = [0, 1, 8, 16];
+const CONST: [usize; 4] = [0, 1, 8, 16];
+
 fn calc_idx(i: usize) -> usize {
     (i + i + 20) % 4
 }
 
 fn main() {
-    let ns = [2, 3, 5, 7];
+    const MAX_LEN: usize = 42;
+
+    let ns = vec![2, 3, 5, 7];
 
     for i in 3..10 {
         println!("{}", ns[i]);
@@ -41,7 +48,7 @@ fn main() {
     let g = vec![1, 2, 3, 4, 5, 6];
     let glen = g.len();
     for i in 0..glen {
-        let x: u32 = g[i+1..].iter().sum();
+        let x: u32 = g[i + 1..].iter().sum();
         println!("{}", g[i] + x);
     }
     assert_eq!(g, vec![20, 18, 15, 11, 6, 0]);
@@ -49,7 +56,123 @@ fn main() {
     let mut g = vec![1, 2, 3, 4, 5, 6];
     let glen = g.len();
     for i in 0..glen {
-        g[i] = g[i+1..].iter().sum();
+        g[i] = g[i + 1..].iter().sum();
     }
     assert_eq!(g, vec![20, 18, 15, 11, 6, 0]);
+
+    let x = 5;
+    let mut vec = vec![0; 9];
+
+    for i in x..x + 4 {
+        vec[i] += 1;
+    }
+
+    let x = 5;
+    let mut vec = vec![0; 10];
+
+    for i in x..=x + 4 {
+        vec[i] += 1;
+    }
+
+    let arr = [1, 2, 3];
+
+    for i in 0..3 {
+        println!("{}", arr[i]);
+    }
+
+    for i in 0..2 {
+        println!("{}", arr[i]);
+    }
+
+    for i in 1..3 {
+        println!("{}", arr[i]);
+    }
+
+    let mut vec = vec![1, 2, 3, 4];
+    let vec2 = vec![1, 2, 3, 4];
+    for i in 0..vec.len() {
+        println!("{}", vec[i]);
+    }
+
+    for i in 0..vec.len() {
+        let i = 42; // make a different `i`
+        println!("{}", vec[i]); // ok, not the `i` of the for-loop
+    }
+
+    for i in 0..vec.len() {
+        let _ = vec[i];
+    }
+
+    // ICE #746
+    for j in 0..4 {
+        println!("{:?}", STATIC[j]);
+    }
+
+    for j in 0..4 {
+        println!("{:?}", CONST[j]);
+    }
+
+    for i in 0..vec.len() {
+        println!("{} {}", vec[i], i);
+    }
+    for i in 0..vec.len() {
+        // not an error, indexing more than one variable
+        println!("{} {}", vec[i], vec2[i]);
+    }
+
+    for i in 0..vec.len() {
+        println!("{}", vec2[i]);
+    }
+
+    for i in 5..vec.len() {
+        println!("{}", vec[i]);
+    }
+
+    for i in 0..MAX_LEN {
+        println!("{}", vec[i]);
+    }
+
+    for i in 0..=MAX_LEN {
+        println!("{}", vec[i]);
+    }
+
+    for i in 5..10 {
+        println!("{}", vec[i]);
+    }
+
+    for i in 5..=10 {
+        println!("{}", vec[i]);
+    }
+
+    for i in 5..vec.len() {
+        println!("{} {}", vec[i], i);
+    }
+
+    for i in 5..10 {
+        println!("{} {}", vec[i], i);
+    }
+
+    // #2542
+    for i in 0..vec.len() {
+        vec[i] = Some(1).unwrap_or_else(|| panic!("error on {}", i));
+    }
+
+    // #3788
+    let test = Test {
+        inner: vec![1, 2, 3, 4],
+    };
+    for i in 0..2 {
+        println!("{}", test[i]);
+    }
+}
+
+struct Test {
+    inner: Vec<usize>,
+}
+
+impl std::ops::Index<usize> for Test {
+    type Output = usize;
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.inner[index]
+    }
 }
index c394469c17bc59bf5f70ce4fb29564fa52c57668..4df07c6f1e52b6b0f2f909f494224e08a0af7d70 100644 (file)
 error: the loop variable `i` is only used to index `ns`.
--> $DIR/needless_range_loop.rs:8:14
-  |
-8 |     for i in 3..10 {
-  |              ^^^^^
-  |
-  = note: `-D needless-range-loop` implied by `-D warnings`
 --> $DIR/needless_range_loop.rs:15:14
+   |
+LL |     for i in 3..10 {
+   |              ^^^^^
+   |
+   = note: `-D clippy::needless-range-loop` implied by `-D warnings`
 help: consider using an iterator
-  |
-8 |     for <item> in ns.iter().take(10).skip(3) {
-  |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+LL |     for <item> in ns.iter().take(10).skip(3) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the loop variable `i` is only used to index `ms`.
-  --> $DIR/needless_range_loop.rs:29:14
+  --> $DIR/needless_range_loop.rs:36:14
    |
-29 |     for i in 0..ms.len() {
+LL |     for i in 0..ms.len() {
    |              ^^^^^^^^^^^
 help: consider using an iterator
    |
-29 |     for <item> in &mut ms {
+LL |     for <item> in &mut ms {
    |         ^^^^^^    ^^^^^^^
 
 error: the loop variable `i` is only used to index `ms`.
-  --> $DIR/needless_range_loop.rs:35:14
+  --> $DIR/needless_range_loop.rs:42:14
    |
-35 |     for i in 0..ms.len() {
+LL |     for i in 0..ms.len() {
    |              ^^^^^^^^^^^
 help: consider using an iterator
    |
-35 |     for <item> in &mut ms {
+LL |     for <item> in &mut ms {
    |         ^^^^^^    ^^^^^^^
 
-error: aborting due to 3 previous errors
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:66:14
+   |
+LL |     for i in x..x + 4 {
+   |              ^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter_mut().skip(x).take(4) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:73:14
+   |
+LL |     for i in x..=x + 4 {
+   |              ^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter_mut().skip(x).take(4 + 1) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `arr`.
+  --> $DIR/needless_range_loop.rs:79:14
+   |
+LL |     for i in 0..3 {
+   |              ^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in &arr {
+   |         ^^^^^^    ^^^^
+
+error: the loop variable `i` is only used to index `arr`.
+  --> $DIR/needless_range_loop.rs:83:14
+   |
+LL |     for i in 0..2 {
+   |              ^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in arr.iter().take(2) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `arr`.
+  --> $DIR/needless_range_loop.rs:87:14
+   |
+LL |     for i in 1..3 {
+   |              ^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in arr.iter().skip(1) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:93:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in &vec {
+   |         ^^^^^^    ^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:102:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in &vec {
+   |         ^^^^^^    ^^^^
+
+error: the loop variable `j` is only used to index `STATIC`.
+  --> $DIR/needless_range_loop.rs:107:14
+   |
+LL |     for j in 0..4 {
+   |              ^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in &STATIC {
+   |         ^^^^^^    ^^^^^^^
+
+error: the loop variable `j` is only used to index `CONST`.
+  --> $DIR/needless_range_loop.rs:111:14
+   |
+LL |     for j in 0..4 {
+   |              ^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in &CONST {
+   |         ^^^^^^    ^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:115:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter().enumerate() {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec2`.
+  --> $DIR/needless_range_loop.rs:123:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec2.iter().take(vec.len()) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:127:14
+   |
+LL |     for i in 5..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().skip(5) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:131:14
+   |
+LL |     for i in 0..MAX_LEN {
+   |              ^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(MAX_LEN) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:135:14
+   |
+LL |     for i in 0..=MAX_LEN {
+   |              ^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(MAX_LEN + 1) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:139:14
+   |
+LL |     for i in 5..10 {
+   |              ^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(10).skip(5) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is only used to index `vec`.
+  --> $DIR/needless_range_loop.rs:143:14
+   |
+LL |     for i in 5..=10 {
+   |              ^^^^^^
+help: consider using an iterator
+   |
+LL |     for <item> in vec.iter().take(10 + 1).skip(5) {
+   |         ^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:147:14
+   |
+LL |     for i in 5..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter().enumerate().skip(5) {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:151:14
+   |
+LL |     for i in 5..10 {
+   |              ^^^^^
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the loop variable `i` is used to index `vec`
+  --> $DIR/needless_range_loop.rs:156:14
+   |
+LL |     for i in 0..vec.len() {
+   |              ^^^^^^^^^^^^
+help: consider using an iterator
+   |
+LL |     for (i, <item>) in vec.iter_mut().enumerate() {
+   |         ^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 22 previous errors
 
index 4739ded7b7ea21f02bf4f319d1cd3e7634423990..939233dbecb3a446b10818af5e6657b9167ad3de 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![warn(needless_return)]
+#![warn(clippy::needless_return)]
 
 fn test_end_of_fn() -> bool {
     if true {
@@ -12,7 +9,7 @@ fn test_end_of_fn() -> bool {
 }
 
 fn test_no_semicolon() -> bool {
-    return true
+    return true;
 }
 
 fn test_if_block() -> bool {
@@ -28,7 +25,7 @@ fn test_match(x: bool) -> bool {
         true => return false,
         false => {
             return true;
-        }
+        },
     }
 }
 
index 42dc6e6594c5b6c1c528e2d6eba12dc0c4f0c614..d7132ce495093eea51a5706537744c40573c68de 100644 (file)
@@ -1,51 +1,51 @@
 error: unneeded return statement
-  --> $DIR/needless_return.rs:11:5
+  --> $DIR/needless_return.rs:8:5
    |
-11 |     return true;
+LL |     return true;
    |     ^^^^^^^^^^^^ help: remove `return` as shown: `true`
    |
-   = note: `-D needless-return` implied by `-D warnings`
+   = note: `-D clippy::needless-return` implied by `-D warnings`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:15:5
+  --> $DIR/needless_return.rs:12:5
    |
-15 |     return true
-   |     ^^^^^^^^^^^ help: remove `return` as shown: `true`
+LL |     return true;
+   |     ^^^^^^^^^^^^ help: remove `return` as shown: `true`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:20:9
+  --> $DIR/needless_return.rs:17:9
    |
-20 |         return true;
+LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return` as shown: `true`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:22:9
+  --> $DIR/needless_return.rs:19:9
    |
-22 |         return false;
+LL |         return false;
    |         ^^^^^^^^^^^^^ help: remove `return` as shown: `false`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:28:17
+  --> $DIR/needless_return.rs:25:17
    |
-28 |         true => return false,
+LL |         true => return false,
    |                 ^^^^^^^^^^^^ help: remove `return` as shown: `false`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:30:13
+  --> $DIR/needless_return.rs:27:13
    |
-30 |             return true;
+LL |             return true;
    |             ^^^^^^^^^^^^ help: remove `return` as shown: `true`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:37:9
+  --> $DIR/needless_return.rs:34:9
    |
-37 |         return true;
+LL |         return true;
    |         ^^^^^^^^^^^^ help: remove `return` as shown: `true`
 
 error: unneeded return statement
-  --> $DIR/needless_return.rs:39:16
+  --> $DIR/needless_return.rs:36:16
    |
-39 |     let _ = || return true;
+LL |     let _ = || return true;
    |                ^^^^^^^^^^^ help: remove `return` as shown: `true`
 
 error: aborting due to 8 previous errors
index 35d5730dda1eb643d3a71fab109c3a8d7ad4f905..bfa005a19f91073c5c31552f22a295b97975f9b0 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(needless_update)]
-#![allow(no_effect)]
+#![warn(clippy::needless_update)]
+#![allow(clippy::no_effect)]
 
 struct S {
     pub a: i32,
index 3e509870d00f89a37c02bbab12d2ed08b545105e..133c834880dd907d3f797b03d79bbe7c7ecc6d45 100644 (file)
@@ -1,10 +1,10 @@
 error: struct update has no effect, all the fields in the struct have already been specified
-  --> $DIR/needless_update.rs:16:23
+  --> $DIR/needless_update.rs:13:23
    |
-16 |     S { a: 1, b: 1, ..base };
+LL |     S { a: 1, b: 1, ..base };
    |                       ^^^^
    |
-   = note: `-D needless-update` implied by `-D warnings`
+   = note: `-D clippy::needless-update` implied by `-D warnings`
 
 error: aborting due to previous error
 
index e739908bc282f2039fd962e9720dc65771e12d02..856a430ba2b55012c413b2506862addb039a23c7 100644 (file)
@@ -4,18 +4,16 @@
 
 use std::cmp::Ordering;
 
-#[warn(neg_cmp_op_on_partial_ord)]
+#[warn(clippy::neg_cmp_op_on_partial_ord)]
 fn main() {
-
     let a_value = 1.0;
     let another_value = 7.0;
 
     // --- Bad ---
 
-
     // Not Less but potentially Greater, Equal or Uncomparable.
     let _not_less = !(a_value < another_value);
-    
+
     // Not Less or Equal but potentially Greater or Uncomparable.
     let _not_less_or_equal = !(a_value <= another_value);
 
@@ -25,12 +23,10 @@ fn main() {
     // Not Greater or Equal but potentially Less or Uncomparable.
     let _not_greater_or_equal = !(a_value >= another_value);
 
-
     // --- Good ---
 
-
     let _not_less = match a_value.partial_cmp(&another_value) {
-        None | Some(Ordering::Greater) | Some(Ordering::Equal)  => true,
+        None | Some(Ordering::Greater) | Some(Ordering::Equal) => true,
         _ => false,
     };
     let _not_less_or_equal = match a_value.partial_cmp(&another_value) {
@@ -46,10 +42,8 @@ fn main() {
         _ => false,
     };
 
-
     // --- Should not trigger ---
 
-
     let _ = a_value < another_value;
     let _ = a_value <= another_value;
     let _ = a_value > another_value;
index ccd3056110090db4dcaefd3919e97f86e74ef608..d05fd34ce33be3f5a497fb868e89d69c55cabfba 100644 (file)
@@ -1,27 +1,27 @@
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:17:21
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:15:21
    |
-17 |     let _not_less = !(a_value < another_value);
+LL |     let _not_less = !(a_value < another_value);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D neg-cmp-op-on-partial-ord` implied by `-D warnings`
+   = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings`
 
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:20:30
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:18:30
    |
-20 |     let _not_less_or_equal = !(a_value <= another_value);
+LL |     let _not_less_or_equal = !(a_value <= another_value);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:23:24
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:21:24
    |
-23 |     let _not_greater = !(a_value > another_value);
+LL |     let _not_greater = !(a_value > another_value);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:26:33
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:24:33
    |
-26 |     let _not_greater_or_equal = !(a_value >= another_value);
+LL |     let _not_greater_or_equal = !(a_value >= another_value);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 4 previous errors
index 367d2d5edfbdd5dcf330b4c9e5f1a711d3343c9f..d4a20ce9db1c843a3419ca44107a1aaf5f52dacd 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(neg_multiply)]
-#![allow(no_effect, unnecessary_operation)]
+#![warn(clippy::neg_multiply)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
 
 use std::ops::Mul;
 
index 1d52ba16eae8e5fd9d99fd507251eb9acc6ea50d..055546554518e7520ad0eb4410004d99f636339d 100644 (file)
@@ -1,15 +1,15 @@
 error: Negation by multiplying with -1
-  --> $DIR/neg_multiply.rs:30:5
+  --> $DIR/neg_multiply.rs:27:5
    |
-30 |     x * -1;
+LL |     x * -1;
    |     ^^^^^^
    |
-   = note: `-D neg-multiply` implied by `-D warnings`
+   = note: `-D clippy::neg-multiply` implied by `-D warnings`
 
 error: Negation by multiplying with -1
-  --> $DIR/neg_multiply.rs:32:5
+  --> $DIR/neg_multiply.rs:29:5
    |
-32 |     -1 * x;
+LL |     -1 * x;
    |     ^^^^^^
 
 error: aborting due to 2 previous errors
index 2050012666207d7f3f7d641c03b65c4f06f1b86e..abcec3e92f6a47a145b9a830af1f0a5af6455d3a 100644 (file)
@@ -1,13 +1,17 @@
-
-
-#![allow(single_match, unused_assignments, unused_variables, while_immutable_condition)]
+#![allow(
+    clippy::single_match,
+    unused_assignments,
+    unused_variables,
+    clippy::while_immutable_condition
+)]
 
 fn test1() {
     let mut x = 0;
-    loop { // never_loop
+    loop {
+        // clippy::never_loop
         x += 1;
         if x == 1 {
-            return
+            return;
         }
         break;
     }
@@ -18,16 +22,17 @@ fn test2() {
     loop {
         x += 1;
         if x == 1 {
-            break
+            break;
         }
     }
 }
 
 fn test3() {
     let mut x = 0;
-    loop { // never loops
+    loop {
+        // never loops
         x += 1;
-        break
+        break;
     }
 }
 
@@ -44,24 +49,29 @@ fn test4() {
 
 fn test5() {
     let i = 0;
-       loop { // never loops
-        while i == 0 { // never loops
-            break
+    loop {
+        // never loops
+        while i == 0 {
+            // never loops
+            break;
         }
-        return
-       }
+        return;
+    }
 }
 
 fn test6() {
     let mut x = 0;
     'outer: loop {
         x += 1;
-               loop { // never loops
-            if x == 5 { break }
-                       continue 'outer
-               }
-               return
-       }
+        loop {
+            // never loops
+            if x == 5 {
+                break;
+            }
+            continue 'outer;
+        }
+        return;
+    }
 }
 
 fn test7() {
@@ -72,7 +82,7 @@ fn test7() {
             1 => continue,
             _ => (),
         }
-        return
+        return;
     }
 }
 
@@ -89,13 +99,15 @@ fn test8() {
 
 fn test9() {
     let x = Some(1);
-    while let Some(y) = x { // never loops
-        return
+    while let Some(y) = x {
+        // never loops
+        return;
     }
 }
 
 fn test10() {
-    for x in 0..10 { // never loops
+    for x in 0..10 {
+        // never loops
         match x {
             1 => break,
             _ => return,
@@ -108,7 +120,7 @@ fn test11<F: FnMut() -> i32>(mut f: F) {
         return match f() {
             1 => continue,
             _ => (),
-        }
+        };
     }
 }
 
@@ -128,7 +140,8 @@ pub fn test12(a: bool, b: bool) {
 
 pub fn test13() {
     let mut a = true;
-    loop { // infinite loop
+    loop {
+        // infinite loop
         while a {
             if true {
                 a = false;
@@ -141,11 +154,12 @@ pub fn test13() {
 
 pub fn test14() {
     let mut a = true;
-    'outer: while a { // never loops
+    'outer: while a {
+        // never loops
         while a {
             if a {
                 a = false;
-                continue
+                continue;
             }
         }
         break 'outer;
@@ -177,4 +191,3 @@ fn main() {
     test13();
     test14();
 }
-
index 664be379e357942ae9ab36e34d2b4cfe2662d5f8..416e14d676e7e7f87f4c6e4ee32c34f50a5d6f7d 100644 (file)
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:7:5
+  --> $DIR/never_loop.rs:10:5
    |
-7  | /     loop { // never_loop
-8  | |         x += 1;
-9  | |         if x == 1 {
-10 | |             return
-11 | |         }
-12 | |         break;
-13 | |     }
+LL | /     loop {
+LL | |         // clippy::never_loop
+LL | |         x += 1;
+LL | |         if x == 1 {
+...  |
+LL | |         break;
+LL | |     }
    | |_____^
    |
-   = note: #[deny(never_loop)] on by default
+   = note: #[deny(clippy::never_loop)] on by default
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:28:5
+  --> $DIR/never_loop.rs:32:5
    |
-28 | /     loop { // never loops
-29 | |         x += 1;
-30 | |         break
-31 | |     }
+LL | /     loop {
+LL | |         // never loops
+LL | |         x += 1;
+LL | |         break;
+LL | |     }
    | |_____^
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:47:2
+  --> $DIR/never_loop.rs:52:5
    |
-47 |       loop { // never loops
-   |  _____^
-48 | |         while i == 0 { // never loops
-49 | |             break
-50 | |         }
-51 | |         return
-52 | |     }
+LL | /     loop {
+LL | |         // never loops
+LL | |         while i == 0 {
+LL | |             // never loops
+...  |
+LL | |         return;
+LL | |     }
    | |_____^
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:48:9
+  --> $DIR/never_loop.rs:54:9
    |
-48 | /         while i == 0 { // never loops
-49 | |             break
-50 | |         }
+LL | /         while i == 0 {
+LL | |             // never loops
+LL | |             break;
+LL | |         }
    | |_________^
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:59:3
+  --> $DIR/never_loop.rs:66:9
    |
-59 |           loop { // never loops
-   |  _________^
-60 | |             if x == 5 { break }
-61 | |             continue 'outer
-62 | |         }
+LL | /         loop {
+LL | |             // never loops
+LL | |             if x == 5 {
+LL | |                 break;
+LL | |             }
+LL | |             continue 'outer;
+LL | |         }
    | |_________^
 
 error: this loop never actually loops
-  --> $DIR/never_loop.rs:92:5
+  --> $DIR/never_loop.rs:102:5
    |
-92 | /     while let Some(y) = x { // never loops
-93 | |         return
-94 | |     }
+LL | /     while let Some(y) = x {
+LL | |         // never loops
+LL | |         return;
+LL | |     }
    | |_____^
 
 error: this loop never actually loops
-   --> $DIR/never_loop.rs:98:5
-    |
-98  | /     for x in 0..10 { // never loops
-99  | |         match x {
-100 | |             1 => break,
-101 | |             _ => return,
-102 | |         }
-103 | |     }
-    | |_____^
+  --> $DIR/never_loop.rs:109:5
+   |
+LL | /     for x in 0..10 {
+LL | |         // never loops
+LL | |         match x {
+LL | |             1 => break,
+LL | |             _ => return,
+LL | |         }
+LL | |     }
+   | |_____^
 
 error: this loop never actually loops
-   --> $DIR/never_loop.rs:144:5
-    |
-144 | /     'outer: while a { // never loops
-145 | |         while a {
-146 | |             if a {
-147 | |                 a = false;
-...   |
-151 | |         break 'outer;
-152 | |     }
-    | |_____^
+  --> $DIR/never_loop.rs:157:5
+   |
+LL | /     'outer: while a {
+LL | |         // never loops
+LL | |         while a {
+LL | |             if a {
+...  |
+LL | |         break 'outer;
+LL | |     }
+   | |_____^
 
 error: this loop never actually loops
-   --> $DIR/never_loop.rs:158:9
-    |
-158 | /         while false {
-159 | |             break 'label;
-160 | |         }
-    | |_________^
+  --> $DIR/never_loop.rs:172:9
+   |
+LL | /         while false {
+LL | |             break 'label;
+LL | |         }
+   | |_________^
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/new_ret_no_self.rs b/tests/ui/new_ret_no_self.rs
new file mode 100644 (file)
index 0000000..a31f046
--- /dev/null
@@ -0,0 +1,201 @@
+#![warn(clippy::new_ret_no_self)]
+#![allow(dead_code, clippy::trivially_copy_pass_by_ref)]
+
+fn main() {}
+
+trait R {
+    type Item;
+}
+
+trait Q {
+    type Item;
+    type Item2;
+}
+
+struct S;
+
+impl R for S {
+    type Item = Self;
+}
+
+impl S {
+    // should not trigger the lint
+    pub fn new() -> impl R<Item = Self> {
+        S
+    }
+}
+
+struct S2;
+
+impl R for S2 {
+    type Item = Self;
+}
+
+impl S2 {
+    // should not trigger the lint
+    pub fn new(_: String) -> impl R<Item = Self> {
+        S2
+    }
+}
+
+struct S3;
+
+impl R for S3 {
+    type Item = u32;
+}
+
+impl S3 {
+    // should trigger the lint
+    pub fn new(_: String) -> impl R<Item = u32> {
+        S3
+    }
+}
+
+struct S4;
+
+impl Q for S4 {
+    type Item = u32;
+    type Item2 = Self;
+}
+
+impl S4 {
+    // should not trigger the lint
+    pub fn new(_: String) -> impl Q<Item = u32, Item2 = Self> {
+        S4
+    }
+}
+
+struct T;
+
+impl T {
+    // should not trigger lint
+    pub fn new() -> Self {
+        unimplemented!();
+    }
+}
+
+struct U;
+
+impl U {
+    // should trigger lint
+    pub fn new() -> u32 {
+        unimplemented!();
+    }
+}
+
+struct V;
+
+impl V {
+    // should trigger lint
+    pub fn new(_: String) -> u32 {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerOk;
+
+impl TupleReturnerOk {
+    // should not trigger lint
+    pub fn new() -> (Self, u32) {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerOk2;
+
+impl TupleReturnerOk2 {
+    // should not trigger lint (it doesn't matter which element in the tuple is Self)
+    pub fn new() -> (u32, Self) {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerOk3;
+
+impl TupleReturnerOk3 {
+    // should not trigger lint (tuple can contain multiple Self)
+    pub fn new() -> (Self, Self) {
+        unimplemented!();
+    }
+}
+
+struct TupleReturnerBad;
+
+impl TupleReturnerBad {
+    // should trigger lint
+    pub fn new() -> (u32, u32) {
+        unimplemented!();
+    }
+}
+
+struct MutPointerReturnerOk;
+
+impl MutPointerReturnerOk {
+    // should not trigger lint
+    pub fn new() -> *mut Self {
+        unimplemented!();
+    }
+}
+
+struct MutPointerReturnerOk2;
+
+impl MutPointerReturnerOk2 {
+    // should not trigger lint
+    pub fn new() -> *const Self {
+        unimplemented!();
+    }
+}
+
+struct MutPointerReturnerBad;
+
+impl MutPointerReturnerBad {
+    // should trigger lint
+    pub fn new() -> *mut V {
+        unimplemented!();
+    }
+}
+
+struct GenericReturnerOk;
+
+impl GenericReturnerOk {
+    // should not trigger lint
+    pub fn new() -> Option<Self> {
+        unimplemented!();
+    }
+}
+
+struct GenericReturnerBad;
+
+impl GenericReturnerBad {
+    // should trigger lint
+    pub fn new() -> Option<u32> {
+        unimplemented!();
+    }
+}
+
+struct NestedReturnerOk;
+
+impl NestedReturnerOk {
+    // should not trigger lint
+    pub fn new() -> (Option<Self>, u32) {
+        unimplemented!();
+    }
+}
+
+struct NestedReturnerOk2;
+
+impl NestedReturnerOk2 {
+    // should not trigger lint
+    pub fn new() -> ((Self, u32), u32) {
+        unimplemented!();
+    }
+}
+
+struct NestedReturnerOk3;
+
+impl NestedReturnerOk3 {
+    // should not trigger lint
+    pub fn new() -> Option<(Self, u32)> {
+        unimplemented!();
+    }
+}
diff --git a/tests/ui/new_ret_no_self.stderr b/tests/ui/new_ret_no_self.stderr
new file mode 100644 (file)
index 0000000..dd5a24b
--- /dev/null
@@ -0,0 +1,52 @@
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:49:5
+   |
+LL | /     pub fn new(_: String) -> impl R<Item = u32> {
+LL | |         S3
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:81:5
+   |
+LL | /     pub fn new() -> u32 {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:90:5
+   |
+LL | /     pub fn new(_: String) -> u32 {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:126:5
+   |
+LL | /     pub fn new() -> (u32, u32) {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:153:5
+   |
+LL | /     pub fn new() -> *mut V {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:171:5
+   |
+LL | /     pub fn new() -> Option<u32> {
+LL | |         unimplemented!();
+LL | |     }
+   | |_____^
+
+error: aborting due to 6 previous errors
+
index c06c9f9e962201a5a05c7cc46e3a81e6ed6fbe15..82aec070b404bdaef3dee8701af51e545cedef23 100644 (file)
@@ -1,35 +1,43 @@
 #![feature(const_fn)]
-
-
 #![allow(dead_code)]
-#![warn(new_without_default, new_without_default_derive)]
+#![warn(clippy::new_without_default)]
 
 pub struct Foo;
 
 impl Foo {
-    pub fn new() -> Foo { Foo }
+    pub fn new() -> Foo {
+        Foo
+    }
 }
 
 pub struct Bar;
 
 impl Bar {
-    pub fn new() -> Self { Bar }
+    pub fn new() -> Self {
+        Bar
+    }
 }
 
 pub struct Ok;
 
 impl Ok {
-    pub fn new() -> Self { Ok }
+    pub fn new() -> Self {
+        Ok
+    }
 }
 
 impl Default for Ok {
-    fn default() -> Self { Ok }
+    fn default() -> Self {
+        Ok
+    }
 }
 
 pub struct Params;
 
 impl Params {
-    pub fn new(_: u32) -> Self { Params }
+    pub fn new(_: u32) -> Self {
+        Params
+    }
 }
 
 pub struct GenericsOk<T> {
@@ -37,11 +45,15 @@ pub struct GenericsOk<T> {
 }
 
 impl<U> Default for GenericsOk<U> {
-    fn default() -> Self { unimplemented!(); }
+    fn default() -> Self {
+        unimplemented!();
+    }
 }
 
 impl<'c, V> GenericsOk<V> {
-    pub fn new() -> GenericsOk<V> { unimplemented!() }
+    pub fn new() -> GenericsOk<V> {
+        unimplemented!()
+    }
 }
 
 pub struct LtOk<'a> {
@@ -49,11 +61,15 @@ pub struct LtOk<'a> {
 }
 
 impl<'b> Default for LtOk<'b> {
-    fn default() -> Self { unimplemented!(); }
+    fn default() -> Self {
+        unimplemented!();
+    }
 }
 
 impl<'c> LtOk<'c> {
-    pub fn new() -> LtOk<'c> { unimplemented!() }
+    pub fn new() -> LtOk<'c> {
+        unimplemented!()
+    }
 }
 
 pub struct LtKo<'a> {
@@ -61,26 +77,34 @@ pub struct LtKo<'a> {
 }
 
 impl<'c> LtKo<'c> {
-    pub fn new() -> LtKo<'c> { unimplemented!() }
+    pub fn new() -> LtKo<'c> {
+        unimplemented!()
+    }
     // FIXME: that suggestion is missing lifetimes
 }
 
 struct Private;
 
 impl Private {
-    fn new() -> Private { unimplemented!() } // We don't lint private items
+    fn new() -> Private {
+        unimplemented!()
+    } // We don't lint private items
 }
 
 struct Const;
 
 impl Const {
-    pub const fn new() -> Const { Const } // const fns can't be implemented via Default
+    pub const fn new() -> Const {
+        Const
+    } // const fns can't be implemented via Default
 }
 
 pub struct IgnoreGenericNew;
 
 impl IgnoreGenericNew {
-    pub fn new<T>() -> Self { IgnoreGenericNew } // the derived Default does not make sense here as the result depends on T
+    pub fn new<T>() -> Self {
+        IgnoreGenericNew
+    } // the derived Default does not make sense here as the result depends on T
 }
 
 pub trait TraitWithNew: Sized {
@@ -89,4 +113,39 @@ fn new() -> Self {
     }
 }
 
+pub struct IgnoreUnsafeNew;
+
+impl IgnoreUnsafeNew {
+    pub unsafe fn new() -> Self {
+        IgnoreUnsafeNew
+    }
+}
+
+#[derive(Default)]
+pub struct OptionRefWrapper<'a, T: 'a>(Option<&'a T>);
+
+impl<'a, T: 'a> OptionRefWrapper<'a, T> {
+    pub fn new() -> Self {
+        OptionRefWrapper(None)
+    }
+}
+
+pub struct Allow(Foo);
+
+impl Allow {
+    #[allow(clippy::new_without_default)]
+    pub fn new() -> Self {
+        unimplemented!()
+    }
+}
+
+pub struct AllowDerive;
+
+impl AllowDerive {
+    #[allow(clippy::new_without_default)]
+    pub fn new() -> Self {
+        unimplemented!()
+    }
+}
+
 fn main() {}
index 335e60404fab195730fe0b39ed7d6058f45c385e..cd8e2837f080bed3502877bfcd06c5ae37dbf056 100644 (file)
@@ -1,39 +1,43 @@
 error: you should consider deriving a `Default` implementation for `Foo`
-  --> $DIR/new_without_default.rs:10:5
+  --> $DIR/new_without_default.rs:8:5
    |
-10 |     pub fn new() -> Foo { Foo }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     pub fn new() -> Foo {
+LL | |         Foo
+LL | |     }
+   | |_____^
    |
-   = note: `-D new-without-default-derive` implied by `-D warnings`
+   = note: `-D clippy::new-without-default` implied by `-D warnings`
 help: try this
    |
- | #[derive(Default)]
+LL | #[derive(Default)]
    |
 
 error: you should consider deriving a `Default` implementation for `Bar`
   --> $DIR/new_without_default.rs:16:5
    |
-16 |     pub fn new() -> Self { Bar }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     pub fn new() -> Self {
+LL | |         Bar
+LL | |     }
+   | |_____^
 help: try this
    |
-13 | #[derive(Default)]
+LL | #[derive(Default)]
    |
 
 error: you should consider adding a `Default` implementation for `LtKo<'c>`
-  --> $DIR/new_without_default.rs:64:5
+  --> $DIR/new_without_default.rs:80:5
    |
-64 |     pub fn new() -> LtKo<'c> { unimplemented!() }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D new-without-default` implied by `-D warnings`
+LL | /     pub fn new() -> LtKo<'c> {
+LL | |         unimplemented!()
+LL | |     }
+   | |_____^
 help: try this
    |
-63 | impl Default for LtKo<'c> {
-64 |     fn default() -> Self {
-65 |         Self::new()
-66 |     }
-67 | }
+LL | impl Default for LtKo<'c> {
+LL |     fn default() -> Self {
+LL |         Self::new()
+LL |     }
+LL | }
    |
 
 error: aborting due to 3 previous errors
index 54028cd8b2b69ea1cfac0e986c451c5c1cc1e485..8fbfcb79860a58aa889b872a4c1b663bcf33ed64 100644 (file)
@@ -1,17 +1,15 @@
 #![feature(box_syntax)]
-
-
-#![warn(no_effect, unnecessary_operation)]
+#![warn(clippy::no_effect)]
 #![allow(dead_code)]
 #![allow(path_statements)]
-#![allow(deref_addrof)]
-#![allow(redundant_field_names)]
+#![allow(clippy::deref_addrof)]
+#![allow(clippy::redundant_field_names)]
 #![feature(untagged_unions)]
 
 struct Unit;
 struct Tuple(i32);
 struct Struct {
-    field: i32
+    field: i32,
 }
 enum Enum {
     Tuple(i32),
@@ -22,7 +20,7 @@ impl Drop for DropUnit {
     fn drop(&mut self) {}
 }
 struct DropStruct {
-    field: i32
+    field: i32,
 }
 impl Drop for DropStruct {
     fn drop(&mut self) {}
@@ -46,11 +44,19 @@ union Union {
     b: f64,
 }
 
-fn get_number() -> i32 { 0 }
-fn get_struct() -> Struct { Struct { field: 0 } }
-fn get_drop_struct() -> DropStruct { DropStruct { field: 0 } }
+fn get_number() -> i32 {
+    0
+}
+fn get_struct() -> Struct {
+    Struct { field: 0 }
+}
+fn get_drop_struct() -> DropStruct {
+    DropStruct { field: 0 }
+}
 
-unsafe fn unsafe_fn() -> i32 { 0 }
+unsafe fn unsafe_fn() -> i32 {
+    0
+}
 
 fn main() {
     let s = get_struct();
@@ -93,33 +99,4 @@ fn main() {
     DropTuple(0);
     DropEnum::Tuple(0);
     DropEnum::Struct { field: 0 };
-
-    Tuple(get_number());
-    Struct { field: get_number() };
-    Struct { ..get_struct() };
-    Enum::Tuple(get_number());
-    Enum::Struct { field: get_number() };
-    5 + get_number();
-    *&get_number();
-    &get_number();
-    (5, 6, get_number());
-    box get_number();
-    get_number()..;
-    ..get_number();
-    5..get_number();
-    [42, get_number()];
-    [42, 55][get_number() as usize];
-    (42, get_number()).1;
-    [get_number(); 55];
-    [42; 55][get_number() as usize];
-    {get_number()};
-    FooString { s: String::from("blah"), };
-
-    // Do not warn
-    DropTuple(get_number());
-    DropStruct { field: get_number() };
-    DropStruct { field: get_number() };
-    DropStruct { ..get_drop_struct() };
-    DropEnum::Tuple(get_number());
-    DropEnum::Struct { field: get_number() };
 }
index 7ff0425ebb9c2bf3ef4cbd69276cfaf037b5ef38..834b9056e311df0c0847e6c2e7afb79f6647d9f5 100644 (file)
 error: statement with no effect
-  --> $DIR/no_effect.rs:59:5
+  --> $DIR/no_effect.rs:65:5
    |
-59 |     0;
+LL |     0;
    |     ^^
    |
-   = note: `-D no-effect` implied by `-D warnings`
+   = note: `-D clippy::no-effect` implied by `-D warnings`
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:60:5
+  --> $DIR/no_effect.rs:66:5
    |
-60 |     s2;
+LL |     s2;
    |     ^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:61:5
+  --> $DIR/no_effect.rs:67:5
    |
-61 |     Unit;
+LL |     Unit;
    |     ^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:62:5
+  --> $DIR/no_effect.rs:68:5
    |
-62 |     Tuple(0);
+LL |     Tuple(0);
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:63:5
+  --> $DIR/no_effect.rs:69:5
    |
-63 |     Struct { field: 0 };
+LL |     Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:64:5
+  --> $DIR/no_effect.rs:70:5
    |
-64 |     Struct { ..s };
+LL |     Struct { ..s };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:65:5
+  --> $DIR/no_effect.rs:71:5
    |
-65 |     Union { a: 0 };
+LL |     Union { a: 0 };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:66:5
+  --> $DIR/no_effect.rs:72:5
    |
-66 |     Enum::Tuple(0);
+LL |     Enum::Tuple(0);
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:67:5
+  --> $DIR/no_effect.rs:73:5
    |
-67 |     Enum::Struct { field: 0 };
+LL |     Enum::Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:68:5
+  --> $DIR/no_effect.rs:74:5
    |
-68 |     5 + 6;
+LL |     5 + 6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:69:5
+  --> $DIR/no_effect.rs:75:5
    |
-69 |     *&42;
+LL |     *&42;
    |     ^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:70:5
+  --> $DIR/no_effect.rs:76:5
    |
-70 |     &6;
+LL |     &6;
    |     ^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:71:5
+  --> $DIR/no_effect.rs:77:5
    |
-71 |     (5, 6, 7);
+LL |     (5, 6, 7);
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:72:5
+  --> $DIR/no_effect.rs:78:5
    |
-72 |     box 42;
+LL |     box 42;
    |     ^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:73:5
+  --> $DIR/no_effect.rs:79:5
    |
-73 |     ..;
+LL |     ..;
    |     ^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:74:5
+  --> $DIR/no_effect.rs:80:5
    |
-74 |     5..;
+LL |     5..;
    |     ^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:75:5
+  --> $DIR/no_effect.rs:81:5
    |
-75 |     ..5;
+LL |     ..5;
    |     ^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:76:5
+  --> $DIR/no_effect.rs:82:5
    |
-76 |     5..6;
+LL |     5..6;
    |     ^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:78:5
+  --> $DIR/no_effect.rs:84:5
    |
-78 |     [42, 55];
+LL |     [42, 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:79:5
+  --> $DIR/no_effect.rs:85:5
    |
-79 |     [42, 55][1];
+LL |     [42, 55][1];
    |     ^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:80:5
+  --> $DIR/no_effect.rs:86:5
    |
-80 |     (42, 55).1;
+LL |     (42, 55).1;
    |     ^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:81:5
+  --> $DIR/no_effect.rs:87:5
    |
-81 |     [42; 55];
+LL |     [42; 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:82:5
+  --> $DIR/no_effect.rs:88:5
    |
-82 |     [42; 55][13];
+LL |     [42; 55][13];
    |     ^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:84:5
+  --> $DIR/no_effect.rs:90:5
    |
-84 |     || x += 5;
+LL |     || x += 5;
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> $DIR/no_effect.rs:86:5
+  --> $DIR/no_effect.rs:92:5
    |
-86 |     FooString { s: s };
+LL |     FooString { s: s };
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: statement can be reduced
-  --> $DIR/no_effect.rs:97:5
-   |
-97 |     Tuple(get_number());
-   |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-   |
-   = note: `-D unnecessary-operation` implied by `-D warnings`
-
-error: statement can be reduced
-  --> $DIR/no_effect.rs:98:5
-   |
-98 |     Struct { field: get_number() };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-  --> $DIR/no_effect.rs:99:5
-   |
-99 |     Struct { ..get_struct() };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_struct();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:100:5
-    |
-100 |     Enum::Tuple(get_number());
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:101:5
-    |
-101 |     Enum::Struct { field: get_number() };
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:102:5
-    |
-102 |     5 + get_number();
-    |     ^^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:103:5
-    |
-103 |     *&get_number();
-    |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:104:5
-    |
-104 |     &get_number();
-    |     ^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:105:5
-    |
-105 |     (5, 6, get_number());
-    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `5;6;get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:106:5
-    |
-106 |     box get_number();
-    |     ^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:107:5
-    |
-107 |     get_number()..;
-    |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:108:5
-    |
-108 |     ..get_number();
-    |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:109:5
-    |
-109 |     5..get_number();
-    |     ^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:110:5
-    |
-110 |     [42, get_number()];
-    |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:111:5
-    |
-111 |     [42, 55][get_number() as usize];
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42, 55];get_number() as usize;`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:112:5
-    |
-112 |     (42, get_number()).1;
-    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:113:5
-    |
-113 |     [get_number(); 55];
-    |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:114:5
-    |
-114 |     [42; 55][get_number() as usize];
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42; 55];get_number() as usize;`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:115:5
-    |
-115 |     {get_number()};
-    |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
-
-error: statement can be reduced
-   --> $DIR/no_effect.rs:116:5
-    |
-116 |     FooString { s: String::from("blah"), };
-    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `String::from("blah");`
-
-error: aborting due to 45 previous errors
+error: aborting due to 25 previous errors
 
index d7391577d23ae04583519bef649c651c2733e307..00cbcaeacb9f7d56af93b2f8b675d1997ee3a05e 100644 (file)
@@ -1,11 +1,11 @@
 #![feature(const_string_new, const_vec_new)]
-#![allow(ref_in_deref, dead_code)]
+#![allow(clippy::ref_in_deref, dead_code)]
 
-use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
-use std::cell::Cell;
-use std::sync::Once;
 use std::borrow::Cow;
+use std::cell::Cell;
 use std::fmt::Display;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Once;
 
 const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
 const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
@@ -13,7 +13,9 @@
 //~^ ERROR interior mutable
 
 macro_rules! declare_const {
-    ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; };
+    ($name:ident: $ty:ty = $e:expr) => {
+        const $name: $ty = $e;
+    };
 }
 declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
 
@@ -30,7 +32,7 @@ macro_rules! declare_const {
 static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
 //^ there should be no lints on this line
 
-#[allow(declare_interior_mutable_const)]
+#[allow(clippy::declare_interior_mutable_const)]
 const ONCE_INIT: Once = Once::new();
 
 trait Trait<T>: Copy {
@@ -93,9 +95,6 @@ fn main() {
     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
 
-    ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability
-    assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability
-
     let _once = ONCE_INIT;
     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
@@ -124,7 +123,7 @@ fn main() {
     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
     let _ = ATOMIC_TUPLE.1.into_iter();
     let _ = ATOMIC_TUPLE.2;
-    let _ = &{ATOMIC_TUPLE};
+    let _ = &{ ATOMIC_TUPLE };
 
     CELL.set(2); //~ ERROR interior mutability
     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
index 388c7fabab0e286e308dc8de86876d8f897d8ec9..1276491127ad70ea22c542fab251da1202da3038 100644 (file)
@@ -1,17 +1,17 @@
 error: a const item should never be interior mutable
   --> $DIR/non_copy_const.rs:10:1
    |
-10 | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
+LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable
    | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | |
    | help: make this a static item: `static`
    |
-   = note: #[deny(declare_interior_mutable_const)] on by default
+   = note: #[deny(clippy::declare_interior_mutable_const)] on by default
 
 error: a const item should never be interior mutable
   --> $DIR/non_copy_const.rs:11:1
    |
-11 | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
+LL | const CELL: Cell<usize> = Cell::new(6); //~ ERROR interior mutable
    | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | |
    | help: make this a static item: `static`
@@ -19,257 +19,241 @@ error: a const item should never be interior mutable
 error: a const item should never be interior mutable
   --> $DIR/non_copy_const.rs:12:1
    |
-12 | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
+LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
    | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | |
    | help: make this a static item: `static`
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:16:42
+  --> $DIR/non_copy_const.rs:17:9
    |
-16 |     ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; };
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^
-17 | }
-18 | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
+LL |         const $name: $ty = $e;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable
    | ------------------------------------------ in this macro invocation
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:39:5
+  --> $DIR/non_copy_const.rs:41:5
    |
-39 |     const ATOMIC: AtomicUsize; //~ ERROR interior mutable
+LL |     const ATOMIC: AtomicUsize; //~ ERROR interior mutable
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:43:5
+  --> $DIR/non_copy_const.rs:45:5
    |
-43 |     const INPUT: T;
+LL |     const INPUT: T;
    |     ^^^^^^^^^^^^^^^
    |
 help: consider requiring `T` to be `Copy`
-  --> $DIR/non_copy_const.rs:43:18
+  --> $DIR/non_copy_const.rs:45:18
    |
-43 |     const INPUT: T;
+LL |     const INPUT: T;
    |                  ^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:46:5
+  --> $DIR/non_copy_const.rs:48:5
    |
-46 |     const ASSOC: Self::NonCopyType;
+LL |     const ASSOC: Self::NonCopyType;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider requiring `<Self as Trait<T>>::NonCopyType` to be `Copy`
-  --> $DIR/non_copy_const.rs:46:18
+  --> $DIR/non_copy_const.rs:48:18
    |
-46 |     const ASSOC: Self::NonCopyType;
+LL |     const ASSOC: Self::NonCopyType;
    |                  ^^^^^^^^^^^^^^^^^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:50:5
+  --> $DIR/non_copy_const.rs:52:5
    |
-50 |     const AN_INPUT: T = Self::INPUT;
+LL |     const AN_INPUT: T = Self::INPUT;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider requiring `T` to be `Copy`
-  --> $DIR/non_copy_const.rs:50:21
+  --> $DIR/non_copy_const.rs:52:21
    |
-50 |     const AN_INPUT: T = Self::INPUT;
+LL |     const AN_INPUT: T = Self::INPUT;
    |                     ^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:16:42
+  --> $DIR/non_copy_const.rs:17:9
    |
-16 |     ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; };
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^
+LL |         const $name: $ty = $e;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 ...
-53 |     declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
+LL |     declare_const!(ANOTHER_INPUT: T = Self::INPUT); //~ ERROR interior mutable
    |     ----------------------------------------------- in this macro invocation
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:59:5
+  --> $DIR/non_copy_const.rs:61:5
    |
-59 |     const SELF_2: Self;
+LL |     const SELF_2: Self;
    |     ^^^^^^^^^^^^^^^^^^^
    |
 help: consider requiring `Self` to be `Copy`
-  --> $DIR/non_copy_const.rs:59:19
+  --> $DIR/non_copy_const.rs:61:19
    |
-59 |     const SELF_2: Self;
+LL |     const SELF_2: Self;
    |                   ^^^^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:80:5
+  --> $DIR/non_copy_const.rs:82:5
    |
-80 |     const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
+LL |     const ASSOC_3: AtomicUsize = AtomicUsize::new(14); //~ ERROR interior mutable
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:83:5
+  --> $DIR/non_copy_const.rs:85:5
    |
-83 |     const U_SELF: U = U::SELF_2;
+LL |     const U_SELF: U = U::SELF_2;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider requiring `U` to be `Copy`
-  --> $DIR/non_copy_const.rs:83:19
+  --> $DIR/non_copy_const.rs:85:19
    |
-83 |     const U_SELF: U = U::SELF_2;
+LL |     const U_SELF: U = U::SELF_2;
    |                   ^
 
 error: a const item should never be interior mutable
-  --> $DIR/non_copy_const.rs:86:5
+  --> $DIR/non_copy_const.rs:88:5
    |
-86 |     const T_ASSOC: T::NonCopyType = T::ASSOC;
+LL |     const T_ASSOC: T::NonCopyType = T::ASSOC;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider requiring `<T as Trait<u32>>::NonCopyType` to be `Copy`
-  --> $DIR/non_copy_const.rs:86:20
+  --> $DIR/non_copy_const.rs:88:20
    |
-86 |     const T_ASSOC: T::NonCopyType = T::ASSOC;
+LL |     const T_ASSOC: T::NonCopyType = T::ASSOC;
    |                    ^^^^^^^^^^^^^^
 
 error: a const item with interior mutability should not be borrowed
-  --> $DIR/non_copy_const.rs:93:5
+  --> $DIR/non_copy_const.rs:95:5
    |
-93 |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
+LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^
    |
-   = note: #[deny(borrow_interior_mutable_const)] on by default
+   = note: #[deny(clippy::borrow_interior_mutable_const)] on by default
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-  --> $DIR/non_copy_const.rs:94:16
+  --> $DIR/non_copy_const.rs:96:16
    |
-94 |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
+LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
    |                ^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-  --> $DIR/non_copy_const.rs:96:5
+  --> $DIR/non_copy_const.rs:99:22
    |
-96 |     ATOMIC_USIZE_INIT.store(2, Ordering::SeqCst); //~ ERROR interior mutability
-   |     ^^^^^^^^^^^^^^^^^
+LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
+   |                      ^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-  --> $DIR/non_copy_const.rs:97:16
+  --> $DIR/non_copy_const.rs:100:25
    |
-97 |     assert_eq!(ATOMIC_USIZE_INIT.load(Ordering::SeqCst), 0); //~ ERROR interior mutability
-   |                ^^^^^^^^^^^^^^^^^
+LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
+   |                         ^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:100:22
-    |
-100 |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
-    |                      ^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
-
-error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:101:25
-    |
-101 |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
-    |                         ^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
-
-error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:102:27
-    |
-102 |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
-    |                           ^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:101:27
+   |
+LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
+   |                           ^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:103:26
-    |
-103 |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
-    |                          ^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:102:26
+   |
+LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
+   |                          ^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:114:14
-    |
-114 |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
-    |              ^^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:113:14
+   |
+LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
+   |              ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:115:14
-    |
-115 |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
-    |              ^^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:114:14
+   |
+LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
+   |              ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:116:19
-    |
-116 |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
-    |                   ^^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:115:19
+   |
+LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
+   |                   ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:117:14
-    |
-117 |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
-    |              ^^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:116:14
+   |
+LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+   |              ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:118:13
-    |
-118 |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
-    |             ^^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:117:13
+   |
+LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
+   |             ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:124:13
-    |
-124 |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
-    |             ^^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:123:13
+   |
+LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
+   |             ^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:129:5
-    |
-129 |     CELL.set(2); //~ ERROR interior mutability
-    |     ^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:128:5
+   |
+LL |     CELL.set(2); //~ ERROR interior mutability
+   |     ^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:130:16
-    |
-130 |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
-    |                ^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:129:16
+   |
+LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
+   |                ^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:143:5
-    |
-143 |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
-    |     ^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:142:5
+   |
+LL |     u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability
+   |     ^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
 error: a const item with interior mutability should not be borrowed
-   --> $DIR/non_copy_const.rs:144:16
-    |
-144 |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
-    |                ^^^^^^^^^^^
-    |
-    = help: assign this const to a local or static variable, and use the variable here
+  --> $DIR/non_copy_const.rs:143:16
+   |
+LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability
+   |                ^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
 
-error: aborting due to 31 previous errors
+error: aborting due to 29 previous errors
 
index 19f0889a92c61a2745c4d5e59a8456db122460db..58415b4aede260b668dbd3db7a0f9a56bc56ecd8 100644 (file)
@@ -1,90 +1,5 @@
-
-
-#![warn(clippy,similar_names)]
-#![allow(unused)]
-
-
-struct Foo {
-    apple: i32,
-    bpple: i32,
-}
-
-fn main() {
-    let specter: i32;
-    let spectre: i32;
-
-    let apple: i32;
-
-    let bpple: i32;
-
-    let cpple: i32;
-
-
-    let a_bar: i32;
-    let b_bar: i32;
-    let c_bar: i32;
-
-    let items = [5];
-    for item in &items {
-        loop {}
-    }
-
-    let foo_x: i32;
-    let foo_y: i32;
-
-    let rhs: i32;
-    let lhs: i32;
-
-    let bla_rhs: i32;
-    let bla_lhs: i32;
-
-    let blubrhs: i32;
-    let blublhs: i32;
-
-    let blubx: i32;
-    let bluby: i32;
-
-
-    let cake: i32;
-    let cakes: i32;
-    let coke: i32;
-
-    match 5 {
-        cheese @ 1 => {},
-        rabbit => panic!(),
-    }
-    let cheese: i32;
-    match (42, 43) {
-        (cheese1, 1) => {},
-        (cheese2, 2) => panic!(),
-        _ => println!(""),
-    }
-    let ipv4: i32;
-    let ipv6: i32;
-    let abcd1: i32;
-    let abdc2: i32;
-    let xyz1abc: i32;
-    let xyz2abc: i32;
-    let xyzeabc: i32;
-
-    let parser: i32;
-    let parsed: i32;
-    let parsee: i32;
-
-
-    let setter: i32;
-    let getter: i32;
-    let tx1: i32;
-    let rx1: i32;
-    let tx_cake: i32;
-    let rx_cake: i32;
-}
-
-fn foo() {
-    let Foo { apple, bpple } = unimplemented!();
-    let Foo { apple: spring,
-        bpple: sprang } = unimplemented!();
-}
+#![warn(clippy::all)]
+#![allow(unused, clippy::println_empty_string)]
 
 #[derive(Clone, Debug)]
 enum MaybeInst {
@@ -108,38 +23,23 @@ fn fill(&mut self) {
     }
 }
 
-fn bla() {
-    let a: i32;
-    let (b, c, d): (i32, i64, i16);
-    {
-        {
-            let cdefg: i32;
-            let blar: i32;
-        }
-        {
-            let e: i32;
-        }
-        {
-            let e: i32;
-            let f: i32;
-
-        }
-        match 5 {
-            1 => println!(""),
-            e => panic!(),
-        }
-        match 5 {
-            1 => println!(""),
-            _ => panic!(),
-        }
-    }
-}
-
 fn underscores_and_numbers() {
     let _1 = 1; //~ERROR Consider a more descriptive name
     let ____1 = 1; //~ERROR Consider a more descriptive name
     let __1___2 = 12; //~ERROR Consider a more descriptive name
-    let _1_ok= 1;
+    let _1_ok = 1;
+}
+
+fn issue2927() {
+    let args = 1;
+    format!("{:?}", 2);
+}
+
+fn issue3078() {
+    match "a" {
+        stringify!(a) => {},
+        _ => {},
+    }
 }
 
 struct Bar;
@@ -149,6 +49,8 @@ fn bar() {
         let _1 = 1;
         let ____1 = 1;
         let __1___2 = 12;
-        let _1_ok= 1;
+        let _1_ok = 1;
     }
 }
+
+fn main() {}
index c63b493db8d2fe57b2863a8337c044e6431fbfbc..a0ca46f0efc602cd0a6bccc6c35b48dee5697e5e 100644 (file)
-error: using `println!("")`
-  --> $DIR/non_expressive_names.rs:60:14
-   |
-60 |         _ => println!(""),
-   |              ^^^^^^^^^^^^ help: replace it with: `println!()`
-   |
-   = note: `-D println-empty-string` implied by `-D warnings`
-
-error: using `println!("")`
-   --> $DIR/non_expressive_names.rs:128:18
-    |
-128 |             1 => println!(""),
-    |                  ^^^^^^^^^^^^ help: replace it with: `println!()`
-
-error: using `println!("")`
-   --> $DIR/non_expressive_names.rs:132:18
-    |
-132 |             1 => println!(""),
-    |                  ^^^^^^^^^^^^ help: replace it with: `println!()`
-
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:18:9
-   |
-18 |     let bpple: i32;
-   |         ^^^^^
-   |
-   = note: `-D similar-names` implied by `-D warnings`
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:16:9
-   |
-16 |     let apple: i32;
-   |         ^^^^^
-help: separate the discriminating character by an underscore like: `b_pple`
-  --> $DIR/non_expressive_names.rs:18:9
-   |
-18 |     let bpple: i32;
-   |         ^^^^^
-
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:20:9
-   |
-20 |     let cpple: i32;
-   |         ^^^^^
-   |
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:16:9
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:27:9
    |
-16 |     let apple: i32;
-   |         ^^^^^
-help: separate the discriminating character by an underscore like: `c_pple`
-  --> $DIR/non_expressive_names.rs:20:9
+LL |     let _1 = 1; //~ERROR Consider a more descriptive name
+   |         ^^
    |
-20 |     let cpple: i32;
-   |         ^^^^^
+   = note: `-D clippy::just-underscores-and-digits` implied by `-D warnings`
 
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:45:9
-   |
-45 |     let bluby: i32;
-   |         ^^^^^
-   |
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:44:9
-   |
-44 |     let blubx: i32;
-   |         ^^^^^
-help: separate the discriminating character by an underscore like: `blub_y`
-  --> $DIR/non_expressive_names.rs:45:9
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:28:9
    |
-45 |     let bluby: i32;
+LL |     let ____1 = 1; //~ERROR Consider a more descriptive name
    |         ^^^^^
 
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:50:9
-   |
-50 |     let coke: i32;
-   |         ^^^^
-   |
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:48:9
-   |
-48 |     let cake: i32;
-   |         ^^^^
-
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:68:9
-   |
-68 |     let xyzeabc: i32;
-   |         ^^^^^^^
-   |
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:66:9
+error: consider choosing a more descriptive name
+  --> $DIR/non_expressive_names.rs:29:9
    |
-66 |     let xyz1abc: i32;
+LL |     let __1___2 = 12; //~ERROR Consider a more descriptive name
    |         ^^^^^^^
 
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:72:9
-   |
-72 |     let parsee: i32;
-   |         ^^^^^^
-   |
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:70:9
-   |
-70 |     let parser: i32;
-   |         ^^^^^^
-help: separate the discriminating character by an underscore like: `parse_e`
-  --> $DIR/non_expressive_names.rs:72:9
-   |
-72 |     let parsee: i32;
-   |         ^^^^^^
-
-error: binding's name is too similar to existing binding
-  --> $DIR/non_expressive_names.rs:86:16
-   |
-86 |         bpple: sprang } = unimplemented!();
-   |                ^^^^^^
-   |
-note: existing binding defined here
-  --> $DIR/non_expressive_names.rs:85:22
-   |
-85 |     let Foo { apple: spring,
-   |                      ^^^^^^
-
-error: 5th binding whose name is just one char
-   --> $DIR/non_expressive_names.rs:120:17
-    |
-120 |             let e: i32;
-    |                 ^
-    |
-    = note: `-D many-single-char-names` implied by `-D warnings`
-
-error: 5th binding whose name is just one char
-   --> $DIR/non_expressive_names.rs:123:17
-    |
-123 |             let e: i32;
-    |                 ^
-
-error: 6th binding whose name is just one char
-   --> $DIR/non_expressive_names.rs:124:17
-    |
-124 |             let f: i32;
-    |                 ^
-
-error: 5th binding whose name is just one char
-   --> $DIR/non_expressive_names.rs:129:13
-    |
-129 |             e => panic!(),
-    |             ^
-
 error: consider choosing a more descriptive name
-   --> $DIR/non_expressive_names.rs:139:9
-    |
-139 |     let _1 = 1; //~ERROR Consider a more descriptive name
-    |         ^^
-    |
-    = note: `-D just-underscores-and-digits` implied by `-D warnings`
-
-error: consider choosing a more descriptive name
-   --> $DIR/non_expressive_names.rs:140:9
-    |
-140 |     let ____1 = 1; //~ERROR Consider a more descriptive name
-    |         ^^^^^
-
-error: consider choosing a more descriptive name
-   --> $DIR/non_expressive_names.rs:141:9
-    |
-141 |     let __1___2 = 12; //~ERROR Consider a more descriptive name
-    |         ^^^^^^^
-
-error: consider choosing a more descriptive name
-   --> $DIR/non_expressive_names.rs:149:13
-    |
-149 |         let _1 = 1;
-    |             ^^
+  --> $DIR/non_expressive_names.rs:49:13
+   |
+LL |         let _1 = 1;
+   |             ^^
 
 error: consider choosing a more descriptive name
-   --> $DIR/non_expressive_names.rs:150:13
-    |
-150 |         let ____1 = 1;
-    |             ^^^^^
+  --> $DIR/non_expressive_names.rs:50:13
+   |
+LL |         let ____1 = 1;
+   |             ^^^^^
 
 error: consider choosing a more descriptive name
-   --> $DIR/non_expressive_names.rs:151:13
-    |
-151 |         let __1___2 = 12;
-    |             ^^^^^^^
+  --> $DIR/non_expressive_names.rs:51:13
+   |
+LL |         let __1___2 = 12;
+   |             ^^^^^^^
 
-error: aborting due to 20 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/non_expressive_names.stdout b/tests/ui/non_expressive_names.stdout
new file mode 100644 (file)
index 0000000..e69de29
index 4341e8ea70b883455301d3680eebd2690929da01..ff68d38c73bf52a1feae44a01d06e63937f2748b 100644 (file)
@@ -4,7 +4,7 @@
 
 #[derive(Debug)]
 struct MyErrorWithParam<T> {
-    x: T
+    x: T,
 }
 
 fn main() {
@@ -16,7 +16,7 @@ fn main() {
     // the error type implements `Debug`
     let res2: Result<i32, MyError> = Ok(0);
     res2.ok().expect("oh noes!");
-    let res3: Result<u32, MyErrorWithParam<u8>>= Ok(0);
+    let res3: Result<u32, MyErrorWithParam<u8>> = Ok(0);
     res3.ok().expect("whoof");
     let res4: Result<u32, io::Error> = Ok(0);
     res4.ok().expect("argh");
index da2d3b9500fedc01a2c87f1897a459a04f875c87..99e623131833dec97ddda6a3bca83f52d5100db2 100644 (file)
@@ -1,33 +1,33 @@
 error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`
   --> $DIR/ok_expect.rs:14:5
    |
-14 |     res.ok().expect("disaster!");
+LL |     res.ok().expect("disaster!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D ok-expect` implied by `-D warnings`
+   = note: `-D clippy::ok-expect` implied by `-D warnings`
 
 error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`
   --> $DIR/ok_expect.rs:20:5
    |
-20 |     res3.ok().expect("whoof");
+LL |     res3.ok().expect("whoof");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`
   --> $DIR/ok_expect.rs:22:5
    |
-22 |     res4.ok().expect("argh");
+LL |     res4.ok().expect("argh");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`
   --> $DIR/ok_expect.rs:24:5
    |
-24 |     res5.ok().expect("oops");
+LL |     res5.ok().expect("oops");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: called `ok().expect()` on a Result value. You can call `expect` directly on the `Result`
   --> $DIR/ok_expect.rs:26:5
    |
-26 |     res6.ok().expect("meh");
+LL |     res6.ok().expect("meh");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
index fdc01bcc7bc0f329d6c5aa02bed4d8706e69834d..61db311305276156b91cdfcf64277129205538b5 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![warn(if_let_some_result)]
+#![warn(clippy::if_let_some_result)]
 
 fn str_to_int(x: &str) -> i32 {
     if let Some(y) = x.parse().ok() {
index e1371d924eb6673fca9860aee08e66db738ad752..e3e6c5c46343c6126a8bfe591102b0c4c765cb55 100644 (file)
@@ -1,14 +1,14 @@
 error: Matching on `Some` with `ok()` is redundant
-  --> $DIR/ok_if_let.rs:7:5
+  --> $DIR/ok_if_let.rs:4:5
    |
- | /     if let Some(y) = x.parse().ok() {
- | |         y
- | |     } else {
-10 | |         0
-11 | |     }
+LL | /     if let Some(y) = x.parse().ok() {
+LL | |         y
+LL | |     } else {
+LL | |         0
+LL | |     }
    | |_____^
    |
-   = note: `-D if-let-some-result` implied by `-D warnings`
+   = note: `-D clippy::if-let-some-result` implied by `-D warnings`
    = help: Consider matching on `Ok(y)` and removing the call to `ok` instead
 
 error: aborting due to previous error
index 9eb697571b698a3a3fc64a4b23c54d997d49f586..bf43deca12c03ff4fccef8705223b68561e45591 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![allow(unused_variables, blacklisted_name)]
+#![allow(unused_variables, clippy::blacklisted_name)]
 
 use std::collections::HashSet;
 
@@ -9,7 +6,7 @@ fn main() {
     let tracked_fds: HashSet<i32> = HashSet::new();
     let new_fds = HashSet::new();
     let unwanted = &tracked_fds - &new_fds;
-    
+
     let foo = &5 - &6;
 
     let bar = String::new();
index 4a6ff6fe6dca5419f6c3185942476a6fd32cdd29..f5c5b9702619cb678c26a17f410ed508592ba794 100644 (file)
@@ -1,19 +1,19 @@
 error: needlessly taken reference of both operands
-  --> $DIR/op_ref.rs:13:15
+  --> $DIR/op_ref.rs:10:15
    |
-13 |     let foo = &5 - &6;
+LL |     let foo = &5 - &6;
    |               ^^^^^^^
    |
-   = note: `-D op-ref` implied by `-D warnings`
+   = note: `-D clippy::op-ref` implied by `-D warnings`
 help: use the values directly
    |
-13 |     let foo = 5 - 6;
+LL |     let foo = 5 - 6;
    |               ^   ^
 
 error: taken reference of right operand
-  --> $DIR/op_ref.rs:21:8
+  --> $DIR/op_ref.rs:18:8
    |
-21 |     if b < &a {
+LL |     if b < &a {
    |        ^^^^--
    |            |
    |            help: use the right value directly: `a`
index 514808d41f1eee4923bbaeac929e05f3ef489af2..9063fafbcd040a5c26f9cf043ffd30419f287071 100644 (file)
@@ -1,9 +1,7 @@
-
-
 use std::fs::OpenOptions;
 
 #[allow(unused_must_use)]
-#[warn(nonsensical_open_options)]
+#[warn(clippy::nonsensical_open_options)]
 fn main() {
     OpenOptions::new().read(true).truncate(true).open("foo.txt");
     OpenOptions::new().append(true).truncate(true).open("foo.txt");
index f0d419041523d89f8ebe4f5305649cc3812b168a..addb0c4e1a56548a0b11c07e8b461043211de4d4 100644 (file)
@@ -1,45 +1,45 @@
 error: file opened with "truncate" and "read"
--> $DIR/open_options.rs:8:5
-  |
-8 |     OpenOptions::new().read(true).truncate(true).open("foo.txt");
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D nonsensical-open-options` implied by `-D warnings`
 --> $DIR/open_options.rs:6:5
+   |
+LL |     OpenOptions::new().read(true).truncate(true).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::nonsensical-open-options` implied by `-D warnings`
 
 error: file opened with "append" and "truncate"
--> $DIR/open_options.rs:9:5
-  |
-9 |     OpenOptions::new().append(true).truncate(true).open("foo.txt");
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 --> $DIR/open_options.rs:7:5
+   |
+LL |     OpenOptions::new().append(true).truncate(true).open("foo.txt");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the method "read" is called more than once
-  --> $DIR/open_options.rs:11:5
+  --> $DIR/open_options.rs:9:5
    |
-11 |     OpenOptions::new().read(true).read(false).open("foo.txt");
+LL |     OpenOptions::new().read(true).read(false).open("foo.txt");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the method "create" is called more than once
-  --> $DIR/open_options.rs:12:5
+  --> $DIR/open_options.rs:10:5
    |
-12 |     OpenOptions::new().create(true).create(false).open("foo.txt");
+LL |     OpenOptions::new().create(true).create(false).open("foo.txt");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the method "write" is called more than once
-  --> $DIR/open_options.rs:13:5
+  --> $DIR/open_options.rs:11:5
    |
-13 |     OpenOptions::new().write(true).write(false).open("foo.txt");
+LL |     OpenOptions::new().write(true).write(false).open("foo.txt");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the method "append" is called more than once
-  --> $DIR/open_options.rs:14:5
+  --> $DIR/open_options.rs:12:5
    |
-14 |     OpenOptions::new().append(true).append(false).open("foo.txt");
+LL |     OpenOptions::new().append(true).append(false).open("foo.txt");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: the method "truncate" is called more than once
-  --> $DIR/open_options.rs:15:5
+  --> $DIR/open_options.rs:13:5
    |
-15 |     OpenOptions::new().truncate(true).truncate(false).open("foo.txt");
+LL |     OpenOptions::new().truncate(true).truncate(false).open("foo.txt");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/option_map_or_none.fixed b/tests/ui/option_map_or_none.fixed
new file mode 100644 (file)
index 0000000..e637f97
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+fn main() {
+    let opt = Some(1);
+
+    // Check `OPTION_MAP_OR_NONE`.
+    // Single line case.
+    let _ = opt.and_then(|x| Some(x + 1));
+    // Multi-line case.
+    #[rustfmt::skip]
+    let _ = opt.and_then(|x| {
+                        Some(x + 1)
+                       });
+}
diff --git a/tests/ui/option_map_or_none.rs b/tests/ui/option_map_or_none.rs
new file mode 100644 (file)
index 0000000..4b9b247
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+fn main() {
+    let opt = Some(1);
+
+    // Check `OPTION_MAP_OR_NONE`.
+    // Single line case.
+    let _ = opt.map_or(None, |x| Some(x + 1));
+    // Multi-line case.
+    #[rustfmt::skip]
+    let _ = opt.map_or(None, |x| {
+                        Some(x + 1)
+                       });
+}
diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr
new file mode 100644 (file)
index 0000000..66ed1e9
--- /dev/null
@@ -0,0 +1,25 @@
+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
+   |
+LL |     let _ = opt.map_or(None, |x| Some(x + 1));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using and_then instead: `opt.and_then(|x| Some(x + 1))`
+   |
+   = note: `-D clippy::option-map-or-none` implied by `-D warnings`
+
+error: called `map_or(None, f)` on an Option value. This can be done more directly by calling `and_then(f)` instead
+  --> $DIR/option_map_or_none.rs:11:13
+   |
+LL |       let _ = opt.map_or(None, |x| {
+   |  _____________^
+LL | |                         Some(x + 1)
+LL | |                        });
+   | |_________________________^
+help: try using and_then instead
+   |
+LL |     let _ = opt.and_then(|x| {
+LL |                         Some(x + 1)
+LL |                        });
+   |
+
+error: aborting due to 2 previous errors
+
index 06531e29032601ea2dd197034039afd4cf04ee4d..1d2a3a17ee00b88e05710413b7a9e6f9d91037d0 100644 (file)
@@ -1,4 +1,4 @@
-#![warn(option_map_unit_fn)]
+#![warn(clippy::option_map_unit_fn)]
 #![allow(unused)]
 
 fn do_nothing<T>(_: T) {}
@@ -22,7 +22,7 @@ fn do_option_plus_one(self: &Self, value: usize) -> usize {
         value + 1
     }
 }
-
+#[rustfmt::skip]
 fn option_map_unit_fn() {
     let x = HasOption { field: Some(10) };
 
@@ -96,5 +96,4 @@ fn option_map_unit_fn() {
     y.map(do_nothing);
 }
 
-fn main() {
-}
+fn main() {}
index 3ca57a65b3f3263fc4ccfb7cc1224174b0d7a6d3..16e355ad0b2d37520dc37d715383d69dfac186b7 100644 (file)
@@ -1,17 +1,17 @@
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:32:5
    |
-32 |     x.field.map(do_nothing);
+LL |     x.field.map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(x_field) = x.field { do_nothing(...) }`
    |
-   = note: `-D option-map-unit-fn` implied by `-D warnings`
+   = note: `-D clippy::option-map-unit-fn` implied by `-D warnings`
 
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:34:5
    |
-34 |     x.field.map(do_nothing);
+LL |     x.field.map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(x_field) = x.field { do_nothing(...) }`
@@ -19,7 +19,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:36:5
    |
-36 |     x.field.map(diverge);
+LL |     x.field.map(diverge);
    |     ^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(x_field) = x.field { diverge(...) }`
@@ -27,7 +27,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:42:5
    |
-42 |     x.field.map(|value| x.do_option_nothing(value + captured));
+LL |     x.field.map(|value| x.do_option_nothing(value + captured));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }`
@@ -35,7 +35,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:44:5
    |
-44 |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
+LL |     x.field.map(|value| { x.do_option_plus_one(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }`
@@ -43,7 +43,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:47:5
    |
-47 |     x.field.map(|value| do_nothing(value + captured));
+LL |     x.field.map(|value| do_nothing(value + captured));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
@@ -51,7 +51,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:49:5
    |
-49 |     x.field.map(|value| { do_nothing(value + captured) });
+LL |     x.field.map(|value| { do_nothing(value + captured) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }`
@@ -59,7 +59,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:51:5
    |
-51 |     x.field.map(|value| { do_nothing(value + captured); });
+LL |     x.field.map(|value| { do_nothing(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
@@ -67,7 +67,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:53:5
    |
-53 |     x.field.map(|value| { { do_nothing(value + captured); } });
+LL |     x.field.map(|value| { { do_nothing(value + captured); } });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }`
@@ -75,7 +75,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:56:5
    |
-56 |     x.field.map(|value| diverge(value + captured));
+LL |     x.field.map(|value| diverge(value + captured));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
@@ -83,7 +83,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:58:5
    |
-58 |     x.field.map(|value| { diverge(value + captured) });
+LL |     x.field.map(|value| { diverge(value + captured) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured) }`
@@ -91,7 +91,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:60:5
    |
-60 |     x.field.map(|value| { diverge(value + captured); });
+LL |     x.field.map(|value| { diverge(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
@@ -99,7 +99,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:62:5
    |
-62 |     x.field.map(|value| { { diverge(value + captured); } });
+LL |     x.field.map(|value| { { diverge(value + captured); } });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { diverge(value + captured); }`
@@ -107,7 +107,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:67:5
    |
-67 |     x.field.map(|value| { let y = plus_one(value + captured); });
+LL |     x.field.map(|value| { let y = plus_one(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }`
@@ -115,7 +115,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:69:5
    |
-69 |     x.field.map(|value| { plus_one(value + captured); });
+LL |     x.field.map(|value| { plus_one(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
@@ -123,7 +123,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:71:5
    |
-71 |     x.field.map(|value| { { plus_one(value + captured); } });
+LL |     x.field.map(|value| { { plus_one(value + captured); } });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { plus_one(value + captured); }`
@@ -131,7 +131,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:74:5
    |
-74 |     x.field.map(|ref value| { do_nothing(value + captured) });
+LL |     x.field.map(|ref value| { do_nothing(value + captured) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }`
@@ -139,7 +139,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:77:5
    |
-77 |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { ... }`
@@ -147,7 +147,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:79:5
    |
-79 |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
+LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { ... }`
@@ -155,13 +155,13 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:83:5
    |
-83 |        x.field.map(|value| {
+LL |        x.field.map(|value| {
    |   _____^
    |  |_____|
    | ||
-84 | ||         do_nothing(value);
-85 | ||         do_nothing(value)
-86 | ||     });
+LL | ||         do_nothing(value);
+LL | ||         do_nothing(value)
+LL | ||     });
    | ||______^- help: try this: `if let Some(value) = x.field { ... }`
    | |_______|
    | 
@@ -169,7 +169,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit closure
   --> $DIR/option_map_unit_fn.rs:87:5
    |
-87 |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(value) = x.field { ... }`
@@ -177,7 +177,7 @@ error: called `map(f)` on an Option value where `f` is a unit closure
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:90:5
    |
-90 |     Some(42).map(diverge);
+LL |     Some(42).map(diverge);
    |     ^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(_) = Some(42) { diverge(...) }`
@@ -185,7 +185,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:91:5
    |
-91 |     "12".parse::<i32>().ok().map(diverge);
+LL |     "12".parse::<i32>().ok().map(diverge);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(_) = "12".parse::<i32>().ok() { diverge(...) }`
@@ -193,7 +193,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:92:5
    |
-92 |     Some(plus_one(1)).map(do_nothing);
+LL |     Some(plus_one(1)).map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(_) = Some(plus_one(1)) { do_nothing(...) }`
@@ -201,7 +201,7 @@ error: called `map(f)` on an Option value where `f` is a unit function
 error: called `map(f)` on an Option value where `f` is a unit function
   --> $DIR/option_map_unit_fn.rs:96:5
    |
-96 |     y.map(do_nothing);
+LL |     y.map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Some(_y) = y { do_nothing(...) }`
index 249745c6a4504c68b1f2aa63ad0f8c629c2a496d..e2e649a8108764de4e4a9d0063180486199bdcee 100644 (file)
@@ -1,5 +1,4 @@
-fn input(_: Option<Option<u8>>) {
-}
+fn input(_: Option<Option<u8>>) {}
 
 fn output() -> Option<Option<u8>> {
     None
@@ -30,7 +29,7 @@ trait Trait {
 
 enum Enum {
     Tuple(Option<Option<u8>>),
-    Struct{x: Option<Option<u8>>},
+    Struct { x: Option<Option<u8>> },
 }
 
 // The lint allows this
@@ -59,5 +58,3 @@ fn main() {
     // The lint allows this
     let expr = Some(Some(true));
 }
-
-
index 19e00efae7188d9d2c2277d31f71aa6a05b2b0fe..9e9425cf9540be58eacf1b4c9de19b49e8518e0e 100644 (file)
@@ -1,58 +1,58 @@
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
- --> $DIR/option_option.rs:1:13
-  |
-1 | fn input(_: Option<Option<u8>>) {
-  |             ^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D option-option` implied by `-D warnings`
 --> $DIR/option_option.rs:1:13
+   |
+LL | fn input(_: Option<Option<u8>>) {}
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::option-option` implied by `-D warnings`
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:4:16
-  |
-4 | fn output() -> Option<Option<u8>> {
-  |                ^^^^^^^^^^^^^^^^^^
 --> $DIR/option_option.rs:3:16
+   |
+LL | fn output() -> Option<Option<u8>> {
+   |                ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
--> $DIR/option_option.rs:8:27
-  |
-8 | fn output_nested() -> Vec<Option<Option<u8>>> {
-  |                           ^^^^^^^^^^^^^^^^^^
 --> $DIR/option_option.rs:7:27
+   |
+LL | fn output_nested() -> Vec<Option<Option<u8>>> {
+   |                           ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:13:30
+  --> $DIR/option_option.rs:12:30
    |
-13 | fn output_nested_nested() -> Option<Option<Option<u8>>> {
+LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:18:8
+  --> $DIR/option_option.rs:17:8
    |
-18 |     x: Option<Option<u8>>,
+LL |     x: Option<Option<u8>>,
    |        ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:22:23
+  --> $DIR/option_option.rs:21:23
    |
-22 |     fn struct_fn() -> Option<Option<u8>> {
+LL |     fn struct_fn() -> Option<Option<u8>> {
    |                       ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:28:22
+  --> $DIR/option_option.rs:27:22
    |
-28 |     fn trait_fn() -> Option<Option<u8>>;
+LL |     fn trait_fn() -> Option<Option<u8>>;
    |                      ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:32:11
+  --> $DIR/option_option.rs:31:11
    |
-32 |     Tuple(Option<Option<u8>>),
+LL |     Tuple(Option<Option<u8>>),
    |           ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> $DIR/option_option.rs:33:15
+  --> $DIR/option_option.rs:32:17
    |
-33 |     Struct{x: Option<Option<u8>>},
-   |               ^^^^^^^^^^^^^^^^^^
+LL |     Struct { x: Option<Option<u8>> },
+   |                 ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
 
diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs
new file mode 100644 (file)
index 0000000..f339bae
--- /dev/null
@@ -0,0 +1,99 @@
+#![warn(clippy::or_fun_call)]
+
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::time::Duration;
+
+/// Checks implementation of the `OR_FUN_CALL` lint.
+fn or_fun_call() {
+    struct Foo;
+
+    impl Foo {
+        fn new() -> Foo {
+            Foo
+        }
+    }
+
+    enum Enum {
+        A(i32),
+    }
+
+    fn make<T>() -> T {
+        unimplemented!();
+    }
+
+    let with_enum = Some(Enum::A(1));
+    with_enum.unwrap_or(Enum::A(5));
+
+    let with_const_fn = Some(Duration::from_secs(1));
+    with_const_fn.unwrap_or(Duration::from_secs(5));
+
+    let with_constructor = Some(vec![1]);
+    with_constructor.unwrap_or(make());
+
+    let with_new = Some(vec![1]);
+    with_new.unwrap_or(Vec::new());
+
+    let with_const_args = Some(vec![1]);
+    with_const_args.unwrap_or(Vec::with_capacity(12));
+
+    let with_err: Result<_, ()> = Ok(vec![1]);
+    with_err.unwrap_or(make());
+
+    let with_err_args: Result<_, ()> = Ok(vec![1]);
+    with_err_args.unwrap_or(Vec::with_capacity(12));
+
+    let with_default_trait = Some(1);
+    with_default_trait.unwrap_or(Default::default());
+
+    let with_default_type = Some(1);
+    with_default_type.unwrap_or(u64::default());
+
+    let with_vec = Some(vec![1]);
+    with_vec.unwrap_or(vec![]);
+
+    // FIXME #944: ~|SUGGESTION with_vec.unwrap_or_else(|| vec![]);
+
+    let without_default = Some(Foo);
+    without_default.unwrap_or(Foo::new());
+
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
+
+    let stringy = Some(String::from(""));
+    let _ = stringy.unwrap_or("".to_owned());
+
+    let opt = Some(1);
+    let hello = "Hello";
+    let _ = opt.ok_or(format!("{} world.", hello));
+}
+
+struct Foo(u8);
+struct Bar(String, Duration);
+#[rustfmt::skip]
+fn test_or_with_ctors() {
+    let opt = Some(1);
+    let opt_opt = Some(Some(1));
+    // we also test for const promotion, this makes sure we don't hit that
+    let two = 2;
+
+    let _ = opt_opt.unwrap_or(Some(2));
+    let _ = opt_opt.unwrap_or(Some(two));
+    let _ = opt.ok_or(Some(2));
+    let _ = opt.ok_or(Some(two));
+    let _ = opt.ok_or(Foo(2));
+    let _ = opt.ok_or(Foo(two));
+    let _ = opt.or(Some(2));
+    let _ = opt.or(Some(two));
+
+    let _ = Some("a".to_string()).or(Some("b".to_string()));
+
+    let b = "b".to_string();
+    let _ = Some(Bar("a".to_string(), Duration::from_secs(1)))
+        .or(Some(Bar(b, Duration::from_secs(2))));
+}
+
+fn main() {}
diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr
new file mode 100644 (file)
index 0000000..f6e5d20
--- /dev/null
@@ -0,0 +1,88 @@
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:32:22
+   |
+LL |     with_constructor.unwrap_or(make());
+   |                      ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
+   |
+   = note: `-D clippy::or-fun-call` implied by `-D warnings`
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:35:5
+   |
+LL |     with_new.unwrap_or(Vec::new());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:38:21
+   |
+LL |     with_const_args.unwrap_or(Vec::with_capacity(12));
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:41:14
+   |
+LL |     with_err.unwrap_or(make());
+   |              ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:44:19
+   |
+LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
+
+error: use of `unwrap_or` followed by a call to `default`
+  --> $DIR/or_fun_call.rs:47:5
+   |
+LL |     with_default_trait.unwrap_or(Default::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `default`
+  --> $DIR/or_fun_call.rs:50:5
+   |
+LL |     with_default_type.unwrap_or(u64::default());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:53:14
+   |
+LL |     with_vec.unwrap_or(vec![]);
+   |              ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| vec![])`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:58:21
+   |
+LL |     without_default.unwrap_or(Foo::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:61:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:64:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:67:21
+   |
+LL |     let _ = stringy.unwrap_or("".to_owned());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
+
+error: use of `ok_or` followed by a function call
+  --> $DIR/or_fun_call.rs:71:17
+   |
+LL |     let _ = opt.ok_or(format!("{} world.", hello));
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `ok_or_else(|| format!("{} world.", hello))`
+
+error: use of `or` followed by a function call
+  --> $DIR/or_fun_call.rs:92:35
+   |
+LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
+
+error: aborting due to 14 previous errors
+
index 889c339c8fdac7a95e7b2db7ef01a91653a1aae1..84332040dbadbdb1e55bd34e2c696d5a1d7f2ba1 100644 (file)
@@ -1,61 +1,26 @@
-
-
-
-#![allow(many_single_char_names)]
-#![warn(overflow_check_conditional)]
+#![allow(clippy::many_single_char_names)]
+#![warn(clippy::overflow_check_conditional)]
 
 fn main() {
-       let a: u32 = 1;
-       let b: u32 = 2;
-       let c: u32 = 3;
-       if a + b < a {
-
-       }
-       if a > a + b {
-
-       }
-       if a + b < b {
-
-       }
-       if b > a + b {
-
-       }
-       if a - b > b {
-
-       }
-       if b < a - b {
-
-       }
-       if a - b > a {
-
-       }
-       if a < a - b {
-
-       }
-       if a + b < c {
-
-       }
-       if c > a + b {
-
-       }
-       if a - b < c {
-
-       }
-       if c > a - b {
-
-       }
-       let i = 1.1;
-       let j = 2.2;
-       if i + j < i {
-
-       }
-       if i - j < i {
-
-       }
-       if i > i + j {
-
-       }
-       if i - j < i {
-
-       }
+    let a: u32 = 1;
+    let b: u32 = 2;
+    let c: u32 = 3;
+    if a + b < a {}
+    if a > a + b {}
+    if a + b < b {}
+    if b > a + b {}
+    if a - b > b {}
+    if b < a - b {}
+    if a - b > a {}
+    if a < a - b {}
+    if a + b < c {}
+    if c > a + b {}
+    if a - b < c {}
+    if c > a - b {}
+    let i = 1.1;
+    let j = 2.2;
+    if i + j < i {}
+    if i - j < i {}
+    if i > i + j {}
+    if i - j < i {}
 }
index adf353a1c4bc11f50a4b8d43431aad51293dd96a..ad66135d326bdcf51538f817b48a4455a396dc7c 100644 (file)
@@ -1,51 +1,51 @@
 error: You are trying to use classic C overflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:11:5
+  --> $DIR/overflow_check_conditional.rs:8:8
    |
-11 |     if a + b < a {
+LL |     if a + b < a {}
    |        ^^^^^^^^^
    |
-   = note: `-D overflow-check-conditional` implied by `-D warnings`
+   = note: `-D clippy::overflow-check-conditional` implied by `-D warnings`
 
 error: You are trying to use classic C overflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:14:5
+  --> $DIR/overflow_check_conditional.rs:9:8
    |
-14 |     if a > a + b {
+LL |     if a > a + b {}
    |        ^^^^^^^^^
 
 error: You are trying to use classic C overflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:17:5
+  --> $DIR/overflow_check_conditional.rs:10:8
    |
-17 |     if a + b < b {
+LL |     if a + b < b {}
    |        ^^^^^^^^^
 
 error: You are trying to use classic C overflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:20:5
+  --> $DIR/overflow_check_conditional.rs:11:8
    |
-20 |     if b > a + b {
+LL |     if b > a + b {}
    |        ^^^^^^^^^
 
 error: You are trying to use classic C underflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:23:5
+  --> $DIR/overflow_check_conditional.rs:12:8
    |
-23 |     if a - b > b {
+LL |     if a - b > b {}
    |        ^^^^^^^^^
 
 error: You are trying to use classic C underflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:26:5
+  --> $DIR/overflow_check_conditional.rs:13:8
    |
-26 |     if b < a - b {
+LL |     if b < a - b {}
    |        ^^^^^^^^^
 
 error: You are trying to use classic C underflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:29:5
+  --> $DIR/overflow_check_conditional.rs:14:8
    |
-29 |     if a - b > a {
+LL |     if a - b > a {}
    |        ^^^^^^^^^
 
 error: You are trying to use classic C underflow conditions that will fail in Rust.
-  --> $DIR/overflow_check_conditional.rs:32:5
+  --> $DIR/overflow_check_conditional.rs:15:8
    |
-32 |     if a < a - b {
+LL |     if a < a - b {}
    |        ^^^^^^^^^
 
 error: aborting due to 8 previous errors
index 33050633f7fbae22e7564daa37673da9d3604a43..92290da8a6ac0c1a495533196b98e8a65d856f86 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(panic_params, unimplemented)]
-
+#![warn(clippy::panic_params, clippy::unimplemented)]
+#![allow(clippy::assertions_on_constants)]
 fn missing() {
     if true {
         panic!("{}");
@@ -36,7 +33,7 @@ fn ok_bracket() {
     }
 }
 
-const ONE : u32= 1;
+const ONE: u32 = 1;
 
 fn ok_nomsg() {
     assert!({ 1 == ONE });
index 3bf5589c46825675eb94839b3c55faa1bb84774e..588fa187b4ab07b8619472988378bb1424bc6a8b 100644 (file)
@@ -1,36 +1,36 @@
 error: you probably are missing some parameter in your format string
--> $DIR/panic_unimplemented.rs:8:16
-  |
-8 |         panic!("{}");
-  |                ^^^^
-  |
-  = note: `-D panic-params` implied by `-D warnings`
 --> $DIR/panic_unimplemented.rs:5:16
+   |
+LL |         panic!("{}");
+   |                ^^^^
+   |
+   = note: `-D clippy::panic-params` implied by `-D warnings`
 
 error: you probably are missing some parameter in your format string
-  --> $DIR/panic_unimplemented.rs:10:16
+  --> $DIR/panic_unimplemented.rs:7:16
    |
-10 |         panic!("{:?}");
+LL |         panic!("{:?}");
    |                ^^^^^^
 
 error: you probably are missing some parameter in your format string
-  --> $DIR/panic_unimplemented.rs:12:23
+  --> $DIR/panic_unimplemented.rs:9:23
    |
-12 |         assert!(true, "here be missing values: {}");
+LL |         assert!(true, "here be missing values: {}");
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you probably are missing some parameter in your format string
-  --> $DIR/panic_unimplemented.rs:15:12
+  --> $DIR/panic_unimplemented.rs:12:12
    |
-15 |     panic!("{{{this}}}");
+LL |     panic!("{{{this}}}");
    |            ^^^^^^^^^^^^
 
 error: `unimplemented` should not be present in production code
-  --> $DIR/panic_unimplemented.rs:58:5
+  --> $DIR/panic_unimplemented.rs:55:5
    |
-58 |     unimplemented!();
+LL |     unimplemented!();
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D unimplemented` implied by `-D warnings`
+   = note: `-D clippy::unimplemented` implied by `-D warnings`
 
 error: aborting due to 5 previous errors
 
index 36dd4df8a6ecdb612221c658c18eb6cec8000adf..1338d3c74d5540117bb54666b5fa35ce56ed1a25 100644 (file)
@@ -1,13 +1,26 @@
-
-
-
 #![allow(dead_code)]
 
 struct Foo;
 
 impl PartialEq for Foo {
-    fn eq(&self, _: &Foo) -> bool { true }
-    fn ne(&self, _: &Foo) -> bool { false }
+    fn eq(&self, _: &Foo) -> bool {
+        true
+    }
+    fn ne(&self, _: &Foo) -> bool {
+        false
+    }
+}
+
+struct Bar;
+
+impl PartialEq for Bar {
+    fn eq(&self, _: &Bar) -> bool {
+        true
+    }
+    #[allow(clippy::partialeq_ne_impl)]
+    fn ne(&self, _: &Bar) -> bool {
+        false
+    }
 }
 
 fn main() {}
index 5e536cc51d28e722a7a5a2b41f186ba39fc48bee..b92da4511b48d03ee50bc6a91d23ac40aef285e3 100644 (file)
@@ -1,10 +1,12 @@
 error: re-implementing `PartialEq::ne` is unnecessary
-  --> $DIR/partialeq_ne_impl.rs:10:5
+  --> $DIR/partialeq_ne_impl.rs:9:5
    |
-10 |     fn ne(&self, _: &Foo) -> bool { false }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | /     fn ne(&self, _: &Foo) -> bool {
+LL | |         false
+LL | |     }
+   | |_____^
    |
-   = note: `-D partialeq-ne-impl` implied by `-D warnings`
+   = note: `-D clippy::partialeq-ne-impl` implied by `-D warnings`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/path_buf_push_overwrite.fixed b/tests/ui/path_buf_push_overwrite.fixed
new file mode 100644 (file)
index 0000000..ef88568
--- /dev/null
@@ -0,0 +1,8 @@
+// run-rustfix
+use std::path::PathBuf;
+
+#[warn(clippy::all, clippy::path_buf_push_overwrite)]
+fn main() {
+    let mut x = PathBuf::from("/foo");
+    x.push("bar");
+}
diff --git a/tests/ui/path_buf_push_overwrite.rs b/tests/ui/path_buf_push_overwrite.rs
new file mode 100644 (file)
index 0000000..6e2d483
--- /dev/null
@@ -0,0 +1,8 @@
+// run-rustfix
+use std::path::PathBuf;
+
+#[warn(clippy::all, clippy::path_buf_push_overwrite)]
+fn main() {
+    let mut x = PathBuf::from("/foo");
+    x.push("/bar");
+}
diff --git a/tests/ui/path_buf_push_overwrite.stderr b/tests/ui/path_buf_push_overwrite.stderr
new file mode 100644 (file)
index 0000000..09b18d7
--- /dev/null
@@ -0,0 +1,10 @@
+error: Calling `push` with '/' or '/' (file system root) will overwrite the previous path definition
+  --> $DIR/path_buf_push_overwrite.rs:7:12
+   |
+LL |     x.push("/bar");
+   |            ^^^^^^ help: try: `"bar"`
+   |
+   = note: `-D clippy::path-buf-push-overwrite` implied by `-D warnings`
+
+error: aborting due to previous error
+
index 65e319e2f8811c3dfbfa8966d7b02318c99314bb..576e6c9ab92a97d287726b9e9ad80af794c68501 100644 (file)
@@ -1,16 +1,14 @@
-
-
 #![allow(unused)]
-#![warn(clippy)]
+#![warn(clippy::all)]
 
 fn main() {
     let v = Some(true);
     match v {
         Some(x) => (),
-        y @ _   => (),
+        y @ _ => (),
     }
     match v {
-        Some(x)  => (),
-        y @ None => (),  // no error
+        Some(x) => (),
+        y @ None => (), // no error
     }
 }
index 59bce3a9a8f6d427d3e0f606f1b0ff3ce5ad4e5f..39dc034a01415d4f39295a72f13a505e60334d2e 100644 (file)
@@ -1,10 +1,10 @@
 error: the `y @ _` pattern can be written as just `y`
-  --> $DIR/patterns.rs:10:9
+  --> $DIR/patterns.rs:8:9
    |
-10 |         y @ _   => (),
+LL |         y @ _ => (),
    |         ^^^^^
    |
-   = note: `-D redundant-pattern` implied by `-D warnings`
+   = note: `-D clippy::redundant-pattern` implied by `-D warnings`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/precedence.fixed b/tests/ui/precedence.fixed
new file mode 100644 (file)
index 0000000..0ec85bc
--- /dev/null
@@ -0,0 +1,37 @@
+// run-rustfix
+#![warn(clippy::precedence)]
+#![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+macro_rules! trip {
+    ($a:expr) => {
+        match $a & 0b1111_1111u8 {
+            0 => println!("a is zero ({})", $a),
+            _ => println!("a is {}", $a),
+        }
+    };
+}
+
+fn main() {
+    1 << (2 + 3);
+    (1 + 2) << 3;
+    4 >> (1 + 1);
+    (1 + 3) >> 2;
+    1 ^ (1 - 1);
+    3 | (2 - 1);
+    3 & (5 - 2);
+    -(1i32.abs());
+    -(1f32.abs());
+
+    // These should not trigger an error
+    let _ = (-1i32).abs();
+    let _ = (-1f32).abs();
+    let _ = -(1i32).abs();
+    let _ = -(1f32).abs();
+    let _ = -(1i32.abs());
+    let _ = -(1f32.abs());
+
+    let b = 3;
+    trip!(b * 8);
+}
index aacd90cdf92b73e0bd8a6a8cc67c6935523ce76d..4ef771c314f51e22c1785d3bad5e0f0fc5071bbd 100644 (file)
@@ -1,17 +1,16 @@
-
-
-
-#[warn(precedence)]
-#[allow(identity_op)]
-#[allow(eq_op)]
+// run-rustfix
+#![warn(clippy::precedence)]
+#![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
 
 macro_rules! trip {
-   ($a:expr) => {
-    match $a & 0b1111_1111i8 {
-        0 => println!("a is zero ({})", $a),
-        _ => println!("a is {}", $a),
-    }
-   };
+    ($a:expr) => {
+        match $a & 0b1111_1111u8 {
+            0 => println!("a is zero ({})", $a),
+            _ => println!("a is {}", $a),
+        }
+    };
 }
 
 fn main() {
index 92c1364746e8fe4d8f848685341f2c154253f519..a2ed5392bfc7c643593dbf24434ab8c05d1d3c93 100644 (file)
@@ -1,57 +1,57 @@
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:18:5
+  --> $DIR/precedence.rs:17:5
    |
-18 |     1 << 2 + 3;
+LL |     1 << 2 + 3;
    |     ^^^^^^^^^^ help: consider parenthesizing your expression: `1 << (2 + 3)`
    |
-   = note: `-D precedence` implied by `-D warnings`
+   = note: `-D clippy::precedence` implied by `-D warnings`
 
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:19:5
+  --> $DIR/precedence.rs:18:5
    |
-19 |     1 + 2 << 3;
+LL |     1 + 2 << 3;
    |     ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3`
 
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:20:5
+  --> $DIR/precedence.rs:19:5
    |
-20 |     4 >> 1 + 1;
+LL |     4 >> 1 + 1;
    |     ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)`
 
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:21:5
+  --> $DIR/precedence.rs:20:5
    |
-21 |     1 + 3 >> 2;
+LL |     1 + 3 >> 2;
    |     ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2`
 
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:22:5
+  --> $DIR/precedence.rs:21:5
    |
-22 |     1 ^ 1 - 1;
+LL |     1 ^ 1 - 1;
    |     ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)`
 
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:23:5
+  --> $DIR/precedence.rs:22:5
    |
-23 |     3 | 2 - 1;
+LL |     3 | 2 - 1;
    |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)`
 
 error: operator precedence can trip the unwary
-  --> $DIR/precedence.rs:24:5
+  --> $DIR/precedence.rs:23:5
    |
-24 |     3 & 5 - 2;
+LL |     3 & 5 - 2;
    |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)`
 
 error: unary minus has lower precedence than method call
-  --> $DIR/precedence.rs:25:5
+  --> $DIR/precedence.rs:24:5
    |
-25 |     -1i32.abs();
+LL |     -1i32.abs();
    |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1i32.abs())`
 
 error: unary minus has lower precedence than method call
-  --> $DIR/precedence.rs:26:5
+  --> $DIR/precedence.rs:25:5
    |
-26 |     -1f32.abs();
+LL |     -1f32.abs();
    |     ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())`
 
 error: aborting due to 9 previous errors
index 8719a691d43538958991539fc4acbf98185cdb58..366ccc2b3bd584bb79d53cf918631a9496c7e053 100644 (file)
@@ -1,7 +1,5 @@
-
-
-#![allow(print_literal, write_literal)]
-#![warn(print_stdout, use_debug)]
+#![allow(clippy::print_literal, clippy::write_literal)]
+#![warn(clippy::print_stdout, clippy::use_debug)]
 
 use std::fmt::{Debug, Display, Formatter, Result};
 
index f2d2afd9bf782d1695e62c94d064c7ac6954ee3f..12c5a0bdaa025f00a325ff245d5a8ec3fac56e59 100644 (file)
@@ -1,59 +1,59 @@
 error: use of `Debug`-based formatting
-  --> $DIR/print.rs:13:19
+  --> $DIR/print.rs:11:19
    |
-13 |         write!(f, "{:?}", 43.1415)
+LL |         write!(f, "{:?}", 43.1415)
    |                   ^^^^^^
    |
-   = note: `-D use-debug` implied by `-D warnings`
+   = note: `-D clippy::use-debug` implied by `-D warnings`
 
 error: use of `Debug`-based formatting
-  --> $DIR/print.rs:20:19
+  --> $DIR/print.rs:18:19
    |
-20 |         write!(f, "{:?}", 42.718)
+LL |         write!(f, "{:?}", 42.718)
    |                   ^^^^^^
 
 error: use of `println!`
-  --> $DIR/print.rs:25:5
+  --> $DIR/print.rs:23:5
    |
-25 |     println!("Hello");
+LL |     println!("Hello");
    |     ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D print-stdout` implied by `-D warnings`
+   = note: `-D clippy::print-stdout` implied by `-D warnings`
 
 error: use of `print!`
-  --> $DIR/print.rs:26:5
+  --> $DIR/print.rs:24:5
    |
-26 |     print!("Hello");
+LL |     print!("Hello");
    |     ^^^^^^^^^^^^^^^
 
 error: use of `print!`
-  --> $DIR/print.rs:28:5
+  --> $DIR/print.rs:26:5
    |
-28 |     print!("Hello {}", "World");
+LL |     print!("Hello {}", "World");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of `print!`
-  --> $DIR/print.rs:30:5
+  --> $DIR/print.rs:28:5
    |
-30 |     print!("Hello {:?}", "World");
+LL |     print!("Hello {:?}", "World");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of `Debug`-based formatting
-  --> $DIR/print.rs:30:12
+  --> $DIR/print.rs:28:12
    |
-30 |     print!("Hello {:?}", "World");
+LL |     print!("Hello {:?}", "World");
    |            ^^^^^^^^^^^^
 
 error: use of `print!`
-  --> $DIR/print.rs:32:5
+  --> $DIR/print.rs:30:5
    |
-32 |     print!("Hello {:#?}", "#orld");
+LL |     print!("Hello {:#?}", "#orld");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of `Debug`-based formatting
-  --> $DIR/print.rs:32:12
+  --> $DIR/print.rs:30:12
    |
-32 |     print!("Hello {:#?}", "#orld");
+LL |     print!("Hello {:#?}", "#orld");
    |            ^^^^^^^^^^^^^
 
 error: aborting due to 9 previous errors
index 620349bab33591c023cf3d0d73f45683ba9c8733..40ed18e93026353f8830f163b65609e408aa0a0d 100644 (file)
@@ -1,6 +1,4 @@
-
-
-#![warn(print_literal)]
+#![warn(clippy::print_literal)]
 
 fn main() {
     // these should be fine
@@ -8,17 +6,17 @@ fn main() {
     println!("Hello");
     let world = "world";
     println!("Hello {}", world);
-    println!("Hello {world}", world=world);
+    println!("Hello {world}", world = world);
     println!("3 in hex is {:X}", 3);
     println!("2 + 1 = {:.4}", 3);
     println!("2 + 1 = {:5.4}", 3);
     println!("Debug test {:?}", "hello, world");
     println!("{0:8} {1:>8}", "hello", "world");
     println!("{1:8} {0:>8}", "hello", "world");
-    println!("{foo:8} {bar:>8}", foo="hello", bar="world");
-    println!("{bar:8} {foo:>8}", foo="hello", bar="world");
-    println!("{number:>width$}", number=1, width=6);
-    println!("{number:>0width$}", number=1, width=6);
+    println!("{foo:8} {bar:>8}", foo = "hello", bar = "world");
+    println!("{bar:8} {foo:>8}", foo = "hello", bar = "world");
+    println!("{number:>width$}", number = 1, width = 6);
+    println!("{number:>0width$}", number = 1, width = 6);
 
     // these should throw warnings
     println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
@@ -35,6 +33,6 @@ fn main() {
     println!("{1} {0}", "hello", "world");
 
     // named args shouldn't change anything either
-    println!("{foo} {bar}", foo="hello", bar="world");
-    println!("{bar} {foo}", foo="hello", bar="world");
+    println!("{foo} {bar}", foo = "hello", bar = "world");
+    println!("{bar} {foo}", foo = "hello", bar = "world");
 }
index cada26c614231ff3963251475d80889d7496cd12..fc502e9f71d525858d414699d5184b0c98cb8093 100644 (file)
@@ -1,88 +1,88 @@
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:24:71
+  --> $DIR/print_literal.rs:22:71
    |
-24 |     println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
+LL |     println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
    |                                                                       ^
    |
-   = note: `-D print-literal` implied by `-D warnings`
+   = note: `-D clippy::print-literal` implied by `-D warnings`
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:25:24
+  --> $DIR/print_literal.rs:23:24
    |
-25 |     print!("Hello {}", "world");
+LL |     print!("Hello {}", "world");
    |                        ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:26:36
+  --> $DIR/print_literal.rs:24:36
    |
-26 |     println!("Hello {} {}", world, "world");
+LL |     println!("Hello {} {}", world, "world");
    |                                    ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:27:26
+  --> $DIR/print_literal.rs:25:26
    |
-27 |     println!("Hello {}", "world");
+LL |     println!("Hello {}", "world");
    |                          ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:28:30
+  --> $DIR/print_literal.rs:26:30
    |
-28 |     println!("10 / 4 is {}", 2.5);
+LL |     println!("10 / 4 is {}", 2.5);
    |                              ^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:29:28
+  --> $DIR/print_literal.rs:27:28
    |
-29 |     println!("2 + 1 = {}", 3);
+LL |     println!("2 + 1 = {}", 3);
    |                            ^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:34:25
+  --> $DIR/print_literal.rs:32:25
    |
-34 |     println!("{0} {1}", "hello", "world");
+LL |     println!("{0} {1}", "hello", "world");
    |                         ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:34:34
+  --> $DIR/print_literal.rs:32:34
    |
-34 |     println!("{0} {1}", "hello", "world");
+LL |     println!("{0} {1}", "hello", "world");
    |                                  ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:35:25
+  --> $DIR/print_literal.rs:33:25
    |
-35 |     println!("{1} {0}", "hello", "world");
+LL |     println!("{1} {0}", "hello", "world");
    |                         ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:35:34
+  --> $DIR/print_literal.rs:33:34
    |
-35 |     println!("{1} {0}", "hello", "world");
+LL |     println!("{1} {0}", "hello", "world");
    |                                  ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:38:33
+  --> $DIR/print_literal.rs:36:35
    |
-38 |     println!("{foo} {bar}", foo="hello", bar="world");
-   |                                 ^^^^^^^
+LL |     println!("{foo} {bar}", foo = "hello", bar = "world");
+   |                                   ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:38:46
+  --> $DIR/print_literal.rs:36:50
    |
-38 |     println!("{foo} {bar}", foo="hello", bar="world");
-   |                                              ^^^^^^^
+LL |     println!("{foo} {bar}", foo = "hello", bar = "world");
+   |                                                  ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:39:33
+  --> $DIR/print_literal.rs:37:35
    |
-39 |     println!("{bar} {foo}", foo="hello", bar="world");
-   |                                 ^^^^^^^
+LL |     println!("{bar} {foo}", foo = "hello", bar = "world");
+   |                                   ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/print_literal.rs:39:46
+  --> $DIR/print_literal.rs:37:50
    |
-39 |     println!("{bar} {foo}", foo="hello", bar="world");
-   |                                              ^^^^^^^
+LL |     println!("{bar} {foo}", foo = "hello", bar = "world");
+   |                                                  ^^^^^^^
 
 error: aborting due to 14 previous errors
 
index 5445c862096f74153bc3e5ae2220ef6c63c53ebd..1c219ecb325b13ab8aeb9c3fc7d1d06260b0024c 100644 (file)
@@ -1,12 +1,10 @@
-
-
-#![allow(print_literal)]
-#![warn(print_with_newline)]
+#![allow(clippy::print_literal)]
+#![warn(clippy::print_with_newline)]
 
 fn main() {
     print!("Hello\n");
     print!("Hello {}\n", "world");
-    print!("Hello {} {}\n\n", "world", "#2");
+    print!("Hello {} {}\n", "world", "#2");
     print!("{}\n", 1265);
 
     // these are all fine
@@ -18,4 +16,27 @@ fn main() {
     print!("Issue\n{}", 1265);
     print!("{}", 1265);
     print!("\n{}", 1275);
+    print!("\n\n");
+    print!("like eof\n\n");
+    print!("Hello {} {}\n\n", "world", "#2");
+    println!("\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
+    println!("\nbla\n\n"); // #3126
+
+    // Escaping
+    print!("\\n"); // #3514
+    print!("\\\n"); // should fail
+    print!("\\\\n");
+
+    // Raw strings
+    print!(r"\n"); // #3778
+
+    // Literal newlines should also fail
+    print!(
+        "
+"
+    );
+    print!(
+        r"
+"
+    );
 }
index 181f16b5cb71066bb6c80a39181ef0804a850d9a..ff89b0d3fd446762d41ac189428422589b8744a4 100644 (file)
@@ -1,28 +1,52 @@
-error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
--> $DIR/print_with_newline.rs:7:5
-  |
-7 |     print!("Hello/n");
-  |     ^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D print-with-newline` implied by `-D warnings`
-
-error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
--> $DIR/print_with_newline.rs:8:5
-  |
-8 |     print!("Hello {}/n", "world");
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
--> $DIR/print_with_newline.rs:9:5
-  |
-9 |     print!("Hello {} {}/n/n", "world", "#2");
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead
-  --> $DIR/print_with_newline.rs:10:5
-   |
-10 |     print!("{}/n", 1265);
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
 --> $DIR/print_with_newline.rs:5:5
+   |
+LL |     print!("Hello/n");
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::print-with-newline` implied by `-D warnings`
+
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
 --> $DIR/print_with_newline.rs:6:5
+   |
+LL |     print!("Hello {}/n", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
 --> $DIR/print_with_newline.rs:7:5
+   |
+LL |     print!("Hello {} {}/n", "world", "#2");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
+  --> $DIR/print_with_newline.rs:8:5
+   |
+LL |     print!("{}/n", 1265);
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
+  --> $DIR/print_with_newline.rs:27:5
+   |
+LL |     print!("//n"); // should fail
+   |     ^^^^^^^^^^^^^^
+
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
+  --> $DIR/print_with_newline.rs:34:5
+   |
+LL | /     print!(
+LL | |         "
+LL | | "
+LL | |     );
+   | |_____^
+
+error: using `print!()` with a format string that ends in a single newline, consider using `println!()` instead
+  --> $DIR/print_with_newline.rs:38:5
+   |
+LL | /     print!(
+LL | |         r"
+LL | | "
+LL | |     );
+   | |_____^
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed
new file mode 100644 (file)
index 0000000..4e84511
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn main() {
+    println!();
+    println!();
+
+    match "a" {
+        _ => println!(),
+    }
+}
index 9df348050ad70984a1f6f50460217ed53e2002e0..9fdfb03a366916082125fddc9c2187f140af8427 100644 (file)
@@ -1,3 +1,5 @@
+// run-rustfix
+
 fn main() {
     println!();
     println!("");
index cff3f988052a1dd14a6041510d15c7a7bb5b6c21..689624a0fa0fffcf71ee01c500329ce171aa75d2 100644 (file)
@@ -1,16 +1,16 @@
 error: using `println!("")`
--> $DIR/println_empty_string.rs:3:5
-  |
-3 |     println!("");
-  |     ^^^^^^^^^^^^ help: replace it with: `println!()`
-  |
-  = note: `-D println-empty-string` implied by `-D warnings`
 --> $DIR/println_empty_string.rs:5:5
+   |
+LL |     println!("");
+   |     ^^^^^^^^^^^^ help: replace it with: `println!()`
+   |
+   = note: `-D clippy::println-empty-string` implied by `-D warnings`
 
 error: using `println!("")`
--> $DIR/println_empty_string.rs:6:14
-  |
-6 |         _ => println!(""),
-  |              ^^^^^^^^^^^^ help: replace it with: `println!()`
 --> $DIR/println_empty_string.rs:8:14
+   |
+LL |         _ => println!(""),
+   |              ^^^^^^^^^^^^ help: replace it with: `println!()`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/proc_macro.rs b/tests/ui/proc_macro.rs
new file mode 100755 (executable)
index 0000000..dd8bd58
--- /dev/null
@@ -0,0 +1,8 @@
+//! Check that we correctly lint procedural macros.
+
+#![crate_type = "proc-macro"]
+
+#[allow(dead_code)]
+fn f() {
+    let _x = 3.14;
+}
diff --git a/tests/ui/proc_macro.stderr b/tests/ui/proc_macro.stderr
new file mode 100644 (file)
index 0000000..ec19cd8
--- /dev/null
@@ -0,0 +1,10 @@
+error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly
+  --> $DIR/proc_macro.rs:7:14
+   |
+LL |     let _x = 3.14;
+   |              ^^^^
+   |
+   = note: #[deny(clippy::approx_constant)] on by default
+
+error: aborting due to previous error
+
index ce572be7ad8ace96e2e093ca0d8fb00829c79134..1ce6081bf940505af85ff24a35877f32bcbe0b61 100644 (file)
@@ -1,5 +1,5 @@
-#![allow(unused, many_single_char_names)]
-#![warn(ptr_arg)]
+#![allow(unused, clippy::many_single_char_names)]
+#![warn(clippy::ptr_arg)]
 
 use std::borrow::Cow;
 
@@ -7,7 +7,8 @@ fn do_vec(x: &Vec<i64>) {
     //Nothing here
 }
 
-fn do_vec_mut(x: &mut Vec<i64>) { // no error here
+fn do_vec_mut(x: &mut Vec<i64>) {
+    // no error here
     //Nothing here
 }
 
@@ -15,12 +16,12 @@ fn do_str(x: &String) {
     //Nothing here either
 }
 
-fn do_str_mut(x: &mut String) { // no error here
+fn do_str_mut(x: &mut String) {
+    // no error here
     //Nothing here either
 }
 
-fn main() {
-}
+fn main() {}
 
 trait Foo {
     type Item;
@@ -50,9 +51,7 @@ fn str_cloned(x: &String) -> String {
     let a = x.clone();
     let b = x.clone();
     let c = b.clone();
-    let d = a.clone()
-             .clone()
-             .clone();
+    let d = a.clone().clone().clone();
     x.clone()
 }
 
@@ -63,15 +62,25 @@ fn false_positive_capacity(x: &Vec<u8>, y: &String) {
 }
 
 fn false_positive_capacity_too(x: &String) -> String {
-    if x.capacity() > 1024 { panic!("Too large!"); }
+    if x.capacity() > 1024 {
+        panic!("Too large!");
+    }
     x.clone()
 }
 
 #[allow(dead_code)]
-fn test_cow_with_ref(c: &Cow<[i32]>) {
-}
+fn test_cow_with_ref(c: &Cow<[i32]>) {}
 
 #[allow(dead_code)]
 fn test_cow(c: Cow<[i32]>) {
     let _c = c;
 }
+
+trait Foo2 {
+    fn do_string(&self);
+}
+
+// no error for &self references where self is of type String (#2293)
+impl Foo2 for String {
+    fn do_string(&self) {}
+}
index a29e393baa1b464787146cca547555b531ba13dc..34516368e5e4651e6e7556c63d2e15ee13b078c5 100644 (file)
@@ -1,85 +1,85 @@
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
- --> $DIR/ptr_arg.rs:6:14
-  |
-6 | fn do_vec(x: &Vec<i64>) {
-  |              ^^^^^^^^^ help: change this to: `&[i64]`
-  |
-  = note: `-D ptr-arg` implied by `-D warnings`
 --> $DIR/ptr_arg.rs:6:14
+   |
+LL | fn do_vec(x: &Vec<i64>) {
+   |              ^^^^^^^^^ help: change this to: `&[i64]`
+   |
+   = note: `-D clippy::ptr-arg` implied by `-D warnings`
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do.
-  --> $DIR/ptr_arg.rs:14:14
+  --> $DIR/ptr_arg.rs:15:14
    |
-14 | fn do_str(x: &String) {
+LL | fn do_str(x: &String) {
    |              ^^^^^^^ help: change this to: `&str`
 
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
-  --> $DIR/ptr_arg.rs:27:18
+  --> $DIR/ptr_arg.rs:28:18
    |
-27 |     fn do_vec(x: &Vec<i64>);
+LL |     fn do_vec(x: &Vec<i64>);
    |                  ^^^^^^^^^ help: change this to: `&[i64]`
 
 error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
-  --> $DIR/ptr_arg.rs:40:14
+  --> $DIR/ptr_arg.rs:41:14
    |
-40 | fn cloned(x: &Vec<u8>) -> Vec<u8> {
+LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
    |              ^^^^^^^^
 help: change this to
    |
-40 | fn cloned(x: &[u8]) -> Vec<u8> {
+LL | fn cloned(x: &[u8]) -> Vec<u8> {
    |              ^^^^^
 help: change `x.clone()` to
    |
-41 |     let e = x.to_owned();
+LL |     let e = x.to_owned();
    |             ^^^^^^^^^^^^
 help: change `x.clone()` to
    |
-46 |     x.to_owned()
+LL |     x.to_owned()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do.
-  --> $DIR/ptr_arg.rs:49:18
+  --> $DIR/ptr_arg.rs:50:18
    |
-49 | fn str_cloned(x: &String) -> String {
+LL | fn str_cloned(x: &String) -> String {
    |                  ^^^^^^^
 help: change this to
    |
-49 | fn str_cloned(x: &str) -> String {
+LL | fn str_cloned(x: &str) -> String {
    |                  ^^^^
 help: change `x.clone()` to
    |
-50 |     let a = x.to_string();
+LL |     let a = x.to_string();
    |             ^^^^^^^^^^^^^
 help: change `x.clone()` to
    |
-51 |     let b = x.to_string();
+LL |     let b = x.to_string();
    |             ^^^^^^^^^^^^^
 help: change `x.clone()` to
    |
-56 |     x.to_string()
+LL |     x.to_string()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do.
-  --> $DIR/ptr_arg.rs:59:44
+  --> $DIR/ptr_arg.rs:58:44
    |
-59 | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
+LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
    |                                            ^^^^^^^
 help: change this to
    |
-59 | fn false_positive_capacity(x: &Vec<u8>, y: &str) {
+LL | fn false_positive_capacity(x: &Vec<u8>, y: &str) {
    |                                            ^^^^
 help: change `y.clone()` to
    |
-61 |     let b = y.to_string();
+LL |     let b = y.to_string();
    |             ^^^^^^^^^^^^^
 help: change `y.as_str()` to
    |
-62 |     let c = y;
+LL |     let c = y;
    |             ^
 
 error: using a reference to `Cow` is not recommended.
-  --> $DIR/ptr_arg.rs:71:25
+  --> $DIR/ptr_arg.rs:72:25
    |
-71 | fn test_cow_with_ref(c: &Cow<[i32]>) {
+LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
    |                         ^^^^^^^^^^^ help: change this to: `&[i32]`
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed
new file mode 100644 (file)
index 0000000..ebdd6c4
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn main() {
+    let vec = vec![b'a', b'b', b'c'];
+    let ptr = vec.as_ptr();
+
+    let offset_u8 = 1_u8;
+    let offset_usize = 1_usize;
+    let offset_isize = 1_isize;
+
+    unsafe {
+        ptr.add(offset_usize);
+        ptr.offset(offset_isize as isize);
+        ptr.offset(offset_u8 as isize);
+
+        ptr.wrapping_add(offset_usize);
+        ptr.wrapping_offset(offset_isize as isize);
+        ptr.wrapping_offset(offset_u8 as isize);
+    }
+}
diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs
new file mode 100644 (file)
index 0000000..3416c4b
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+fn main() {
+    let vec = vec![b'a', b'b', b'c'];
+    let ptr = vec.as_ptr();
+
+    let offset_u8 = 1_u8;
+    let offset_usize = 1_usize;
+    let offset_isize = 1_isize;
+
+    unsafe {
+        ptr.offset(offset_usize as isize);
+        ptr.offset(offset_isize as isize);
+        ptr.offset(offset_u8 as isize);
+
+        ptr.wrapping_offset(offset_usize as isize);
+        ptr.wrapping_offset(offset_isize as isize);
+        ptr.wrapping_offset(offset_u8 as isize);
+    }
+}
diff --git a/tests/ui/ptr_offset_with_cast.stderr b/tests/ui/ptr_offset_with_cast.stderr
new file mode 100644 (file)
index 0000000..b5c7a03
--- /dev/null
@@ -0,0 +1,16 @@
+error: use of `offset` with a `usize` casted to an `isize`
+  --> $DIR/ptr_offset_with_cast.rs:12:9
+   |
+LL |         ptr.offset(offset_usize as isize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.add(offset_usize)`
+   |
+   = note: `-D clippy::ptr-offset-with-cast` implied by `-D warnings`
+
+error: use of `wrapping_offset` with a `usize` casted to an `isize`
+  --> $DIR/ptr_offset_with_cast.rs:16:9
+   |
+LL |         ptr.wrapping_offset(offset_usize as isize);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)`
+
+error: aborting due to 2 previous errors
+
index 369b868a50d007bfeead1e96ac0442f90b11b01d..56ccf1d432fc462b169d2c66caafd727366f9888 100644 (file)
@@ -1,14 +1,23 @@
 fn some_func(a: Option<u32>) -> Option<u32> {
-       if a.is_none() {
-               return None
-       }
+    if a.is_none() {
+        return None;
+    }
 
-       a
+    a
+}
+
+fn some_other_func(a: Option<u32>) -> Option<u32> {
+    if a.is_none() {
+        return None;
+    } else {
+        return Some(0);
+    }
+    unreachable!()
 }
 
 pub enum SeemsOption<T> {
     Some(T),
-    None
+    None,
 }
 
 impl<T> SeemsOption<T> {
@@ -28,26 +37,74 @@ fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32>
     a
 }
 
-pub struct SomeStruct {
-       pub opt: Option<u32>,
+pub struct CopyStruct {
+    pub opt: Option<u32>,
 }
 
-impl SomeStruct {
-       pub fn func(&self) -> Option<u32> {
-               if (self.opt).is_none() {
-                       return None;
-               }
+impl CopyStruct {
+    #[rustfmt::skip]
+    pub fn func(&self) -> Option<u32> {
+        if (self.opt).is_none() {
+            return None;
+        }
+
+        if self.opt.is_none() {
+            return None
+        }
+
+        let _ = if self.opt.is_none() {
+            return None;
+        } else {
+            self.opt
+        };
+
+        self.opt
+    }
+}
 
-               self.opt
-       }
+#[derive(Clone)]
+pub struct MoveStruct {
+    pub opt: Option<Vec<u32>>,
+}
+
+impl MoveStruct {
+    pub fn ref_func(&self) -> Option<Vec<u32>> {
+        if self.opt.is_none() {
+            return None;
+        }
+
+        self.opt.clone()
+    }
+
+    pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
+        if self.opt.is_none() {
+            return None;
+        }
+
+        self.opt
+    }
+
+    pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
+        if self.opt.is_none() {
+            return None;
+        }
+        Some(Vec::new())
+    }
 }
 
 fn main() {
-       some_func(Some(42));
-       some_func(None);
+    some_func(Some(42));
+    some_func(None);
+
+    let copy_struct = CopyStruct { opt: Some(54) };
+    copy_struct.func();
 
-       let some_struct = SomeStruct { opt: Some(54) };
-       some_struct.func();
+    let move_struct = MoveStruct {
+        opt: Some(vec![42, 1337]),
+    };
+    move_struct.ref_func();
+    move_struct.clone().mov_func_reuse();
+    move_struct.clone().mov_func_no_use();
 
     let so = SeemsOption::Some(45);
     returns_something_similar_to_option(so);
index e97b1869824fcb77895c72402a6a7ff01b0894b6..522501d58c66d49bec578704bcf3e4cde2c96a4e 100644 (file)
@@ -1,22 +1,63 @@
 error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:2:2
-  |
-2 |       if a.is_none() {
-  |  _____^
-3 | |         return None
-4 | |     }
-  | |_____^ help: replace_it_with: `a?;`
-  |
-  = note: `-D question-mark` implied by `-D warnings`
+  --> $DIR/question_mark.rs:2:5
+   |
+LL | /     if a.is_none() {
+LL | |         return None;
+LL | |     }
+   | |_____^ help: replace_it_with: `a?;`
+   |
+   = note: `-D clippy::question-mark` implied by `-D warnings`
 
 error: this block may be rewritten with the `?` operator
-  --> $DIR/question_mark.rs:37:3
+  --> $DIR/question_mark.rs:47:9
    |
-37 |           if (self.opt).is_none() {
-   |  _________^
-38 | |             return None;
-39 | |         }
+LL | /         if (self.opt).is_none() {
+LL | |             return None;
+LL | |         }
    | |_________^ help: replace_it_with: `(self.opt)?;`
 
-error: aborting due to 2 previous errors
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:51:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None
+LL | |         }
+   | |_________^ help: replace_it_with: `self.opt?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:55:17
+   |
+LL |           let _ = if self.opt.is_none() {
+   |  _________________^
+LL | |             return None;
+LL | |         } else {
+LL | |             self.opt
+LL | |         };
+   | |_________^ help: replace_it_with: `Some(self.opt?)`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:72:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace_it_with: `self.opt.as_ref()?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:80:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace_it_with: `self.opt.as_ref()?;`
+
+error: this block may be rewritten with the `?` operator
+  --> $DIR/question_mark.rs:88:9
+   |
+LL | /         if self.opt.is_none() {
+LL | |             return None;
+LL | |         }
+   | |_________^ help: replace_it_with: `self.opt.as_ref()?;`
+
+error: aborting due to 7 previous errors
 
index 611a324f6e3c5fcc719695ac582e1d34a15bc62e..d0c5cc93bd92bc8a51abbaa2e3442d51672c99b3 100644 (file)
@@ -1,11 +1,9 @@
-#![feature(iterator_step_by)]
-
 struct NotARange;
 impl NotARange {
     fn step_by(&self, _: u32) {}
 }
 
-#[warn(iterator_step_by_zero, range_zip_with_len)]
+#[warn(clippy::iterator_step_by_zero, clippy::range_zip_with_len)]
 fn main() {
     let _ = (0..1).step_by(0);
     // No warning for non-zero step
@@ -21,13 +19,13 @@ fn main() {
     let y = NotARange;
     y.step_by(0);
 
-    let v1 = vec![1,2,3];
-    let v2 = vec![4,5];
+    let v1 = vec![1, 2, 3];
+    let v2 = vec![4, 5];
     let _x = v1.iter().zip(0..v1.len());
     let _y = v1.iter().zip(0..v2.len()); // No error
 
     // check const eval
-    let _ = v1.iter().step_by(2/3);
+    let _ = v1.iter().step_by(2 / 3);
 }
 
 #[allow(unused)]
index 064429c337c86a336e67ce5ccd80e26777fbdc12..387d1f674cb275649b0726f27d469058a0583be9 100644 (file)
@@ -1,42 +1,42 @@
 error: Iterator::step_by(0) will panic at runtime
-  --> $DIR/range.rs:10:13
+  --> $DIR/range.rs:8:13
    |
-10 |     let _ = (0..1).step_by(0);
+LL |     let _ = (0..1).step_by(0);
    |             ^^^^^^^^^^^^^^^^^
    |
-   = note: `-D iterator-step-by-zero` implied by `-D warnings`
+   = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings`
 
 error: Iterator::step_by(0) will panic at runtime
-  --> $DIR/range.rs:14:13
+  --> $DIR/range.rs:12:13
    |
-14 |     let _ = (1..).step_by(0);
+LL |     let _ = (1..).step_by(0);
    |             ^^^^^^^^^^^^^^^^
 
 error: Iterator::step_by(0) will panic at runtime
-  --> $DIR/range.rs:15:13
+  --> $DIR/range.rs:13:13
    |
-15 |     let _ = (1..=2).step_by(0);
+LL |     let _ = (1..=2).step_by(0);
    |             ^^^^^^^^^^^^^^^^^^
 
 error: Iterator::step_by(0) will panic at runtime
-  --> $DIR/range.rs:18:13
+  --> $DIR/range.rs:16:13
    |
-18 |     let _ = x.step_by(0);
+LL |     let _ = x.step_by(0);
    |             ^^^^^^^^^^^^
 
 error: It is more idiomatic to use v1.iter().enumerate()
-  --> $DIR/range.rs:26:14
+  --> $DIR/range.rs:24:14
    |
-26 |     let _x = v1.iter().zip(0..v1.len());
+LL |     let _x = v1.iter().zip(0..v1.len());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D range-zip-with-len` implied by `-D warnings`
+   = note: `-D clippy::range-zip-with-len` implied by `-D warnings`
 
 error: Iterator::step_by(0) will panic at runtime
-  --> $DIR/range.rs:30:13
+  --> $DIR/range.rs:28:13
    |
-30 |     let _ = v1.iter().step_by(2/3);
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = v1.iter().step_by(2 / 3);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
index 31574a4aeed6fe582f10039c745db3128ecd64e1..54aec853d3baedc5c9898766c01c9148332aad16 100644 (file)
@@ -2,30 +2,31 @@ fn f() -> usize {
     42
 }
 
-#[warn(range_plus_one)]
+#[warn(clippy::range_plus_one)]
 fn main() {
-    for _ in 0..2 { }
-    for _ in 0..=2 { }
+    for _ in 0..2 {}
+    for _ in 0..=2 {}
 
-    for _ in 0..3+1 { }
-    for _ in 0..=3+1 { }
+    for _ in 0..3 + 1 {}
+    for _ in 0..=3 + 1 {}
 
-    for _ in 0..1+5 { }
-    for _ in 0..=1+5 { }
+    for _ in 0..1 + 5 {}
+    for _ in 0..=1 + 5 {}
 
-    for _ in 1..1+1 { }
-    for _ in 1..=1+1 { }
+    for _ in 1..1 + 1 {}
+    for _ in 1..=1 + 1 {}
 
-    for _ in 0..13+13 { }
-    for _ in 0..=13-7 { }
+    for _ in 0..13 + 13 {}
+    for _ in 0..=13 - 7 {}
 
-    for _ in 0..(1+f()) { }
-    for _ in 0..=(1+f()) { }
+    for _ in 0..(1 + f()) {}
+    for _ in 0..=(1 + f()) {}
 
-    let _ = ..11-1;
-    let _ = ..=11-1;
-    let _ = ..=(11-1);
-    let _ = (f()+1)..(f()+1);
+    let _ = ..11 - 1;
+    let _ = ..=11 - 1;
+    let _ = ..=(11 - 1);
+    let _ = (1..11 + 1);
+    let _ = (f() + 1)..(f() + 1);
 
     let mut vec: Vec<()> = std::vec::Vec::new();
     vec.drain(..);
index 1990300ef90477eca5cedc5449ba57ae08adeb0c..9ebc22e1625334e8737ee45f6744542e4761a220 100644 (file)
@@ -1,48 +1,54 @@
 error: an inclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:10:14
    |
-10 |     for _ in 0..3+1 { }
-   |              ^^^^^^ help: use: `0..=3`
+LL |     for _ in 0..3 + 1 {}
+   |              ^^^^^^^^ help: use: `0..=3`
    |
-   = note: `-D range-plus-one` implied by `-D warnings`
+   = note: `-D clippy::range-plus-one` implied by `-D warnings`
 
 error: an inclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:13:14
    |
-13 |     for _ in 0..1+5 { }
-   |              ^^^^^^ help: use: `0..=5`
+LL |     for _ in 0..1 + 5 {}
+   |              ^^^^^^^^ help: use: `0..=5`
 
 error: an inclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:16:14
    |
-16 |     for _ in 1..1+1 { }
-   |              ^^^^^^ help: use: `1..=1`
+LL |     for _ in 1..1 + 1 {}
+   |              ^^^^^^^^ help: use: `1..=1`
 
 error: an inclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:22:14
    |
-22 |     for _ in 0..(1+f()) { }
-   |              ^^^^^^^^^^ help: use: `0..=f()`
+LL |     for _ in 0..(1 + f()) {}
+   |              ^^^^^^^^^^^^ help: use: `0..=f()`
 
 error: an exclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:26:13
    |
-26 |     let _ = ..=11-1;
-   |             ^^^^^^^ help: use: `..11`
+LL |     let _ = ..=11 - 1;
+   |             ^^^^^^^^^ help: use: `..11`
    |
-   = note: `-D range-minus-one` implied by `-D warnings`
+   = note: `-D clippy::range-minus-one` implied by `-D warnings`
 
 error: an exclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:27:13
    |
-27 |     let _ = ..=(11-1);
-   |             ^^^^^^^^^ help: use: `..11`
+LL |     let _ = ..=(11 - 1);
+   |             ^^^^^^^^^^^ help: use: `..11`
 
 error: an inclusive range would be more readable
   --> $DIR/range_plus_minus_one.rs:28:13
    |
-28 |     let _ = (f()+1)..(f()+1);
-   |             ^^^^^^^^^^^^^^^^ help: use: `(f()+1)..=f()`
+LL |     let _ = (1..11 + 1);
+   |             ^^^^^^^^^^^ help: use: `(1..=11)`
+
+error: an inclusive range would be more readable
+  --> $DIR/range_plus_minus_one.rs:29:13
+   |
+LL |     let _ = (f() + 1)..(f() + 1);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs
new file mode 100644 (file)
index 0000000..6e9ad71
--- /dev/null
@@ -0,0 +1,58 @@
+#![warn(clippy::redundant_clone)]
+
+use std::ffi::OsString;
+use std::path::Path;
+
+fn main() {
+    let _ = ["lorem", "ipsum"].join(" ").to_string();
+
+    let s = String::from("foo");
+    let _ = s.clone();
+
+    let s = String::from("foo");
+    let _ = s.to_string();
+
+    let s = String::from("foo");
+    let _ = s.to_owned();
+
+    let _ = Path::new("/a/b/").join("c").to_owned();
+
+    let _ = Path::new("/a/b/").join("c").to_path_buf();
+
+    let _ = OsString::new().to_owned();
+
+    let _ = OsString::new().to_os_string();
+
+    // Check that lint level works
+    #[allow(clippy::redundant_clone)]
+    let _ = String::new().to_string();
+
+    let tup = (String::from("foo"),);
+    let _ = tup.0.clone();
+
+    let tup_ref = &(String::from("foo"),);
+    let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed
+}
+
+#[derive(Clone)]
+struct Alpha;
+fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) {
+    if b {
+        (a.clone(), a.clone())
+    } else {
+        (Alpha, a)
+    }
+}
+
+struct TypeWithDrop {
+    x: String,
+}
+
+impl Drop for TypeWithDrop {
+    fn drop(&mut self) {}
+}
+
+fn cannot_move_from_type_with_drop() -> String {
+    let s = TypeWithDrop { x: String::new() };
+    s.x.clone() // removing this `clone()` summons E0509
+}
diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr
new file mode 100644 (file)
index 0000000..c8f6cac
--- /dev/null
@@ -0,0 +1,123 @@
+error: redundant clone
+  --> $DIR/redundant_clone.rs:7:41
+   |
+LL |     let _ = ["lorem", "ipsum"].join(" ").to_string();
+   |                                         ^^^^^^^^^^^^ help: remove this
+   |
+   = note: `-D clippy::redundant-clone` implied by `-D warnings`
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:7:13
+   |
+LL |     let _ = ["lorem", "ipsum"].join(" ").to_string();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:10:14
+   |
+LL |     let _ = s.clone();
+   |              ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:10:13
+   |
+LL |     let _ = s.clone();
+   |             ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:13:14
+   |
+LL |     let _ = s.to_string();
+   |              ^^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:13:13
+   |
+LL |     let _ = s.to_string();
+   |             ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:16:14
+   |
+LL |     let _ = s.to_owned();
+   |              ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:16:13
+   |
+LL |     let _ = s.to_owned();
+   |             ^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:18:41
+   |
+LL |     let _ = Path::new("/a/b/").join("c").to_owned();
+   |                                         ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:18:13
+   |
+LL |     let _ = Path::new("/a/b/").join("c").to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:20:41
+   |
+LL |     let _ = Path::new("/a/b/").join("c").to_path_buf();
+   |                                         ^^^^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:20:13
+   |
+LL |     let _ = Path::new("/a/b/").join("c").to_path_buf();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:22:28
+   |
+LL |     let _ = OsString::new().to_owned();
+   |                            ^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:22:13
+   |
+LL |     let _ = OsString::new().to_owned();
+   |             ^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:24:28
+   |
+LL |     let _ = OsString::new().to_os_string();
+   |                            ^^^^^^^^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:24:13
+   |
+LL |     let _ = OsString::new().to_os_string();
+   |             ^^^^^^^^^^^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:31:18
+   |
+LL |     let _ = tup.0.clone();
+   |                  ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:31:13
+   |
+LL |     let _ = tup.0.clone();
+   |             ^^^^^
+
+error: redundant clone
+  --> $DIR/redundant_clone.rs:41:22
+   |
+LL |         (a.clone(), a.clone())
+   |                      ^^^^^^^^ help: remove this
+   |
+note: this value is dropped without further use
+  --> $DIR/redundant_clone.rs:41:21
+   |
+LL |         (a.clone(), a.clone())
+   |                     ^
+
+error: aborting due to 10 previous errors
+
index ab3897bc3150d5e5f74fc64f565917ea8528083b..2304871f2134156f713863cf4668be64e0ab9fae 100644 (file)
@@ -1,21 +1,23 @@
-
-
-
-#![warn(redundant_closure_call)]
+#![warn(clippy::redundant_closure_call)]
 
 fn main() {
-       let a = (|| 42)();
+    let a = (|| 42)();
+
+    let mut i = 1;
+    let mut k = (|m| m + 1)(i);
 
-       let mut i = 1;
-       let mut k = (|m| m+1)(i);
+    k = (|a, b| a * b)(1, 5);
 
-       k = (|a,b| a*b)(1,5);
+    let closure = || 32;
+    i = closure();
 
-       let closure = || 32;
-       i = closure();
+    let closure = |i| i + 1;
+    i = closure(3);
 
-       let closure = |i| i+1;
-       i = closure(3);
+    i = closure(4);
 
-       i = closure(4);
+    #[allow(clippy::needless_return)]
+    (|| return 2)();
+    (|| -> Option<i32> { None? })();
+    (|| -> Result<i32, i32> { r#try!(Err(2)) })();
 }
index d2b5616a4811ef3c261c6352827d85d2cbb99177..9c827fd8f17c616e482f64d73534441f1a1ceb84 100644 (file)
@@ -1,34 +1,34 @@
 error: Closure called just once immediately after it was declared
-  --> $DIR/redundant_closure_call.rs:15:2
+  --> $DIR/redundant_closure_call.rs:12:5
    |
-15 |     i = closure();
+LL |     i = closure();
    |     ^^^^^^^^^^^^^
    |
-   = note: `-D redundant-closure-call` implied by `-D warnings`
+   = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
 
 error: Closure called just once immediately after it was declared
-  --> $DIR/redundant_closure_call.rs:18:2
+  --> $DIR/redundant_closure_call.rs:15:5
    |
-18 |     i = closure(3);
+LL |     i = closure(3);
    |     ^^^^^^^^^^^^^^
 
 error: Try not to call a closure in the expression where it is declared.
- --> $DIR/redundant_closure_call.rs:7:10
-  |
-7 |     let a = (|| 42)();
-  |             ^^^^^^^^^ help: Try doing something like: : `42`
+  --> $DIR/redundant_closure_call.rs:4:13
+   |
+LL |     let a = (|| 42)();
+   |             ^^^^^^^^^ help: Try doing something like: : `42`
 
 error: Try not to call a closure in the expression where it is declared.
-  --> $DIR/redundant_closure_call.rs:10:14
+  --> $DIR/redundant_closure_call.rs:7:17
    |
-10 |     let mut k = (|m| m+1)(i);
-   |                 ^^^^^^^^^^^^
+LL |     let mut k = (|m| m + 1)(i);
+   |                 ^^^^^^^^^^^^^^
 
 error: Try not to call a closure in the expression where it is declared.
-  --> $DIR/redundant_closure_call.rs:12:6
+  --> $DIR/redundant_closure_call.rs:9:9
    |
-12 |     k = (|a,b| a*b)(1,5);
-   |         ^^^^^^^^^^^^^^^^
+LL |     k = (|a, b| a * b)(1, 5);
+   |         ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/redundant_field_names.fixed b/tests/ui/redundant_field_names.fixed
new file mode 100644 (file)
index 0000000..5b4b8ee
--- /dev/null
@@ -0,0 +1,71 @@
+// run-rustfix
+#![warn(clippy::redundant_field_names)]
+#![allow(clippy::no_effect, dead_code, unused_variables)]
+
+#[macro_use]
+extern crate derive_new;
+
+use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
+
+mod foo {
+    pub const BAR: u8 = 0;
+}
+
+struct Person {
+    gender: u8,
+    age: u8,
+    name: u8,
+    buzz: u64,
+    foo: u8,
+}
+
+#[derive(new)]
+pub struct S {
+    v: String,
+}
+
+fn main() {
+    let gender: u8 = 42;
+    let age = 0;
+    let fizz: u64 = 0;
+    let name: u8 = 0;
+
+    let me = Person {
+        gender,
+        age,
+
+        name,          //should be ok
+        buzz: fizz,    //should be ok
+        foo: foo::BAR, //should be ok
+    };
+
+    // Range expressions
+    let (start, end) = (0, 0);
+
+    let _ = start..;
+    let _ = ..end;
+    let _ = start..end;
+
+    let _ = ..=end;
+    let _ = start..=end;
+
+    // Issue #2799
+    let _: Vec<_> = (start..end).collect();
+
+    // hand-written Range family structs are linted
+    let _ = RangeFrom { start };
+    let _ = RangeTo { end };
+    let _ = Range { start, end };
+    let _ = RangeInclusive::new(start, end);
+    let _ = RangeToInclusive { end };
+}
+
+fn issue_3476() {
+    fn foo<T>() {}
+
+    struct S {
+        foo: fn(),
+    }
+
+    S { foo: foo::<i32> };
+}
index 095ac7c0cc15b325b375925eff1b4927b78c513f..3f97b80c56828c3842c451bb9b616bb3103e1eec 100644 (file)
@@ -1,11 +1,11 @@
-#![warn(redundant_field_names)]
-#![allow(unused_variables)]
-#![feature(inclusive_range, inclusive_range_fields, inclusive_range_methods)]
+// run-rustfix
+#![warn(clippy::redundant_field_names)]
+#![allow(clippy::no_effect, dead_code, unused_variables)]
 
 #[macro_use]
 extern crate derive_new;
 
-use std::ops::{Range, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive};
+use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
 
 mod foo {
     pub const BAR: u8 = 0;
@@ -34,8 +34,8 @@ fn main() {
         gender: gender,
         age: age,
 
-        name, //should be ok
-        buzz: fizz, //should be ok
+        name,          //should be ok
+        buzz: fizz,    //should be ok
         foo: foo::BAR, //should be ok
     };
 
@@ -49,6 +49,9 @@ fn main() {
     let _ = ..=end;
     let _ = start..=end;
 
+    // Issue #2799
+    let _: Vec<_> = (start..end).collect();
+
     // hand-written Range family structs are linted
     let _ = RangeFrom { start: start };
     let _ = RangeTo { end: end };
@@ -56,3 +59,13 @@ fn main() {
     let _ = RangeInclusive::new(start, end);
     let _ = RangeToInclusive { end: end };
 }
+
+fn issue_3476() {
+    fn foo<T>() {}
+
+    struct S {
+        foo: fn(),
+    }
+
+    S { foo: foo::<i32> };
+}
index d757f1871a781c4026b24485163b0cd050ef837f..7976292df224140b39a50d44c831c76072467708 100644 (file)
@@ -1,45 +1,45 @@
 error: redundant field names in struct initialization
   --> $DIR/redundant_field_names.rs:34:9
    |
-34 |         gender: gender,
+LL |         gender: gender,
    |         ^^^^^^^^^^^^^^ help: replace it with: `gender`
    |
-   = note: `-D redundant-field-names` implied by `-D warnings`
+   = note: `-D clippy::redundant-field-names` implied by `-D warnings`
 
 error: redundant field names in struct initialization
   --> $DIR/redundant_field_names.rs:35:9
    |
-35 |         age: age,
+LL |         age: age,
    |         ^^^^^^^^ help: replace it with: `age`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:53:25
+  --> $DIR/redundant_field_names.rs:56:25
    |
-53 |     let _ = RangeFrom { start: start };
+LL |     let _ = RangeFrom { start: start };
    |                         ^^^^^^^^^^^^ help: replace it with: `start`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:54:23
+  --> $DIR/redundant_field_names.rs:57:23
    |
-54 |     let _ = RangeTo { end: end };
+LL |     let _ = RangeTo { end: end };
    |                       ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:55:21
+  --> $DIR/redundant_field_names.rs:58:21
    |
-55 |     let _ = Range { start: start, end: end };
+LL |     let _ = Range { start: start, end: end };
    |                     ^^^^^^^^^^^^ help: replace it with: `start`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:55:35
+  --> $DIR/redundant_field_names.rs:58:35
    |
-55 |     let _ = Range { start: start, end: end };
+LL |     let _ = Range { start: start, end: end };
    |                                   ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:57:32
+  --> $DIR/redundant_field_names.rs:60:32
    |
-57 |     let _ = RangeToInclusive { end: end };
+LL |     let _ = RangeToInclusive { end: end };
    |                                ^^^^^^^^ help: replace it with: `end`
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs
new file mode 100644 (file)
index 0000000..8e8d4b5
--- /dev/null
@@ -0,0 +1,54 @@
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+
+fn main() {
+    if let Ok(_) = Ok::<i32, i32>(42) {}
+
+    if let Err(_) = Err::<i32, i32>(42) {}
+
+    if let None = None::<()> {}
+
+    if let Some(_) = Some(42) {}
+
+    if Ok::<i32, i32>(42).is_ok() {}
+
+    if Err::<i32, i32>(42).is_err() {}
+
+    if None::<i32>.is_none() {}
+
+    if Some(42).is_some() {}
+
+    if let Ok(x) = Ok::<i32, i32>(42) {
+        println!("{}", x);
+    }
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        Err(_) => true,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => true,
+        Err(_) => false,
+    };
+
+    match Some(42) {
+        Some(_) => true,
+        None => false,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        None => true,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr
new file mode 100644 (file)
index 0000000..baed95d
--- /dev/null
@@ -0,0 +1,82 @@
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:5:12
+   |
+LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
+   |     -------^^^^^------------------------ help: try this: `if Ok::<i32, i32>(42).is_ok()`
+   |
+   = 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
+   |
+LL |     if let Err(_) = Err::<i32, i32>(42) {}
+   |     -------^^^^^^------------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:9:12
+   |
+LL |     if let None = None::<()> {}
+   |     -------^^^^---------------- help: try this: `if None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:11:12
+   |
+LL |     if let Some(_) = Some(42) {}
+   |     -------^^^^^^^-------------- help: try this: `if Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:25:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:30:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching.rs:35:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         Err(_) => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching.rs:40:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         Err(_) => false,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching.rs:45:5
+   |
+LL | /     match Some(42) {
+LL | |         Some(_) => true,
+LL | |         None => false,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching.rs:50:5
+   |
+LL | /     match None::<()> {
+LL | |         Some(_) => false,
+LL | |         None => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/reference.rs b/tests/ui/reference.rs
deleted file mode 100644 (file)
index 0bd0000..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-fn get_number() -> usize {
-    10
-}
-
-fn get_reference(n : &usize) -> &usize {
-    n
-}
-
-#[allow(many_single_char_names, double_parens)]
-#[allow(unused_variables)]
-#[warn(deref_addrof)]
-fn main() {
-    let a = 10;
-    let aref = &a;
-
-    let b = *&a;
-
-    let b = *&get_number();
-
-    let b = *get_reference(&a);
-
-    let bytes : Vec<usize> = vec![1, 2, 3, 4];
-    let b = *&bytes[1..2][0];
-
-    //This produces a suggestion of 'let b = (a);' which
-    //will trigger the 'unused_parens' lint
-    let b = *&(a);
-
-    let b = *(&a);
-
-    let b = *((&a));
-
-    let b = *&&a;
-
-    let b = **&aref;
-
-    //This produces a suggestion of 'let b = *&a;' which
-    //will trigger the 'deref_addrof' lint again
-    let b = **&&a;
-
-    {
-        let mut x = 10;
-        let y = *&mut x;
-    }
-
-    {
-        //This produces a suggestion of 'let y = *&mut x' which
-        //will trigger the 'deref_addrof' lint again
-        let mut x = 10;
-        let y = **&mut &mut x;
-    }
-}
diff --git a/tests/ui/reference.stderr b/tests/ui/reference.stderr
deleted file mode 100644 (file)
index 741c0cc..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:19:13
-   |
-19 |     let b = *&a;
-   |             ^^^ help: try this: `a`
-   |
-   = note: `-D deref-addrof` implied by `-D warnings`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:21:13
-   |
-21 |     let b = *&get_number();
-   |             ^^^^^^^^^^^^^^ help: try this: `get_number()`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:26:13
-   |
-26 |     let b = *&bytes[1..2][0];
-   |             ^^^^^^^^^^^^^^^^ help: try this: `bytes[1..2][0]`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:30:13
-   |
-30 |     let b = *&(a);
-   |             ^^^^^ help: try this: `(a)`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:32:13
-   |
-32 |     let b = *(&a);
-   |             ^^^^^ help: try this: `a`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:34:13
-   |
-34 |     let b = *((&a));
-   |             ^^^^^^^ help: try this: `a`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:36:13
-   |
-36 |     let b = *&&a;
-   |             ^^^^ help: try this: `&a`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:38:14
-   |
-38 |     let b = **&aref;
-   |              ^^^^^^ help: try this: `aref`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:42:14
-   |
-42 |     let b = **&&a;
-   |              ^^^^ help: try this: `&a`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:46:17
-   |
-46 |         let y = *&mut x;
-   |                 ^^^^^^^ help: try this: `x`
-
-error: immediately dereferencing a reference
-  --> $DIR/reference.rs:53:18
-   |
-53 |         let y = **&mut &mut x;
-   |                  ^^^^^^^^^^^^ help: try this: `&mut x`
-
-error: aborting due to 11 previous errors
-
index b80aaa2df320d8700fc3b5079e7b7c6d5b751eaa..b523fa5b711ae68e611aa3580ea59e9ccc2a7dc9 100644 (file)
@@ -1,13 +1,10 @@
-
-
-
 #![allow(unused)]
-#![warn(invalid_regex, trivial_regex, regex_macro)]
+#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)]
 
 extern crate regex;
 
-use regex::{Regex, RegexSet, RegexBuilder};
-use regex::bytes::{Regex as BRegex, RegexSet as BRegexSet, RegexBuilder as BRegexBuilder};
+use regex::bytes::{Regex as BRegex, RegexBuilder as BRegexBuilder, RegexSet as BRegexSet};
+use regex::{Regex, RegexBuilder, RegexSet};
 
 const OPENING_PAREN: &str = "(";
 const NOT_A_REAL_REGEX: &str = "foobar";
@@ -27,24 +24,15 @@ fn syntax_error() {
     let closing_paren = ")";
     let not_linted = Regex::new(closing_paren);
 
-    let set = RegexSet::new(&[
-        r"[a-z]+@[a-z]+\.(com|org|net)",
-        r"[a-z]+\.(com|org|net)",
-    ]);
+    let set = RegexSet::new(&[r"[a-z]+@[a-z]+\.(com|org|net)", r"[a-z]+\.(com|org|net)"]);
     let bset = BRegexSet::new(&[
         r"[a-z]+@[a-z]+\.(com|org|net)",
         r"[a-z]+\.(com|org|net)",
         r".", // regression test
     ]);
 
-    let set_error = RegexSet::new(&[
-        OPENING_PAREN,
-        r"[a-z]+\.(com|org|net)",
-    ]);
-    let bset_error = BRegexSet::new(&[
-        OPENING_PAREN,
-        r"[a-z]+\.(com|org|net)",
-    ]);
+    let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]);
+    let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]);
 
     let raw_string_error = Regex::new(r"[...\/...]");
     let raw_string_error = Regex::new(r#"[...\/...]"#);
index 39c360583e7d33a2c46e68415a4d46261e8006bf..1394a9b63bc61f3000daa60ab72c3657f8706885 100644 (file)
 error: trivial regex
-  --> $DIR/regex.rs:16:45
+  --> $DIR/regex.rs:13:45
    |
-16 |     let pipe_in_wrong_position = Regex::new("|");
+LL |     let pipe_in_wrong_position = Regex::new("|");
    |                                             ^^^
    |
-   = note: `-D trivial-regex` implied by `-D warnings`
+   = note: `-D clippy::trivial-regex` implied by `-D warnings`
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:17:60
+  --> $DIR/regex.rs:14:60
    |
-17 |     let pipe_in_wrong_position_builder = RegexBuilder::new("|");
+LL |     let pipe_in_wrong_position_builder = RegexBuilder::new("|");
    |                                                            ^^^
    |
    = help: the regex is unlikely to be useful as it is
 
 error: regex syntax error: invalid character class range, the start must be <= the end
-  --> $DIR/regex.rs:18:42
+  --> $DIR/regex.rs:15:42
    |
-18 |     let wrong_char_ranice = Regex::new("[z-a]");
+LL |     let wrong_char_ranice = Regex::new("[z-a]");
    |                                          ^^^
    |
-   = note: `-D invalid-regex` implied by `-D warnings`
+   = note: `-D clippy::invalid-regex` implied by `-D warnings`
 
 error: regex syntax error: invalid character class range, the start must be <= the end
-  --> $DIR/regex.rs:19:37
+  --> $DIR/regex.rs:16:37
    |
-19 |     let some_unicode = Regex::new("[é-è]");
+LL |     let some_unicode = Regex::new("[é-è]");
    |                                     ^^^
 
 error: regex syntax error on position 0: unclosed group
-  --> $DIR/regex.rs:21:33
+  --> $DIR/regex.rs:18:33
    |
-21 |     let some_regex = Regex::new(OPENING_PAREN);
+LL |     let some_regex = Regex::new(OPENING_PAREN);
    |                                 ^^^^^^^^^^^^^
 
 error: trivial regex
-  --> $DIR/regex.rs:23:53
+  --> $DIR/regex.rs:20:53
    |
-23 |     let binary_pipe_in_wrong_position = BRegex::new("|");
+LL |     let binary_pipe_in_wrong_position = BRegex::new("|");
    |                                                     ^^^
    |
    = help: the regex is unlikely to be useful as it is
 
 error: regex syntax error on position 0: unclosed group
-  --> $DIR/regex.rs:24:41
+  --> $DIR/regex.rs:21:41
    |
-24 |     let some_binary_regex = BRegex::new(OPENING_PAREN);
+LL |     let some_binary_regex = BRegex::new(OPENING_PAREN);
    |                                         ^^^^^^^^^^^^^
 
 error: regex syntax error on position 0: unclosed group
-  --> $DIR/regex.rs:25:56
+  --> $DIR/regex.rs:22:56
    |
-25 |     let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
+LL |     let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
    |                                                        ^^^^^^^^^^^^^
 
 error: regex syntax error on position 0: unclosed group
-  --> $DIR/regex.rs:41:9
+  --> $DIR/regex.rs:34:37
    |
-41 |         OPENING_PAREN,
-   |         ^^^^^^^^^^^^^
+LL |     let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
+   |                                     ^^^^^^^^^^^^^
 
 error: regex syntax error on position 0: unclosed group
-  --> $DIR/regex.rs:45:9
+  --> $DIR/regex.rs:35:39
    |
-45 |         OPENING_PAREN,
-   |         ^^^^^^^^^^^^^
+LL |     let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
+   |                                       ^^^^^^^^^^^^^
 
 error: regex syntax error: unrecognized escape sequence
-  --> $DIR/regex.rs:49:45
+  --> $DIR/regex.rs:37:45
    |
-49 |     let raw_string_error = Regex::new(r"[...//...]");
+LL |     let raw_string_error = Regex::new(r"[...//...]");
    |                                             ^^
 
 error: regex syntax error: unrecognized escape sequence
-  --> $DIR/regex.rs:50:46
+  --> $DIR/regex.rs:38:46
    |
-50 |     let raw_string_error = Regex::new(r#"[...//...]"#);
+LL |     let raw_string_error = Regex::new(r#"[...//...]"#);
    |                                              ^^
 
 error: trivial regex
-  --> $DIR/regex.rs:54:33
+  --> $DIR/regex.rs:42:33
    |
-54 |     let trivial_eq = Regex::new("^foobar$");
+LL |     let trivial_eq = Regex::new("^foobar$");
    |                                 ^^^^^^^^^^
    |
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:56:48
+  --> $DIR/regex.rs:44:48
    |
-56 |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
+LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    |                                                ^^^^^^^^^^
    |
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:58:42
+  --> $DIR/regex.rs:46:42
    |
-58 |     let trivial_starts_with = Regex::new("^foobar");
+LL |     let trivial_starts_with = Regex::new("^foobar");
    |                                          ^^^^^^^^^
    |
    = help: consider using `str::starts_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:60:40
+  --> $DIR/regex.rs:48:40
    |
-60 |     let trivial_ends_with = Regex::new("foobar$");
+LL |     let trivial_ends_with = Regex::new("foobar$");
    |                                        ^^^^^^^^^
    |
    = help: consider using `str::ends_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:62:39
+  --> $DIR/regex.rs:50:39
    |
-62 |     let trivial_contains = Regex::new("foobar");
+LL |     let trivial_contains = Regex::new("foobar");
    |                                       ^^^^^^^^
    |
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:64:39
+  --> $DIR/regex.rs:52:39
    |
-64 |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
+LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    |                                       ^^^^^^^^^^^^^^^^
    |
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:66:40
+  --> $DIR/regex.rs:54:40
    |
-66 |     let trivial_backslash = Regex::new("a/.b");
+LL |     let trivial_backslash = Regex::new("a/.b");
    |                                        ^^^^^^^
    |
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:69:36
+  --> $DIR/regex.rs:57:36
    |
-69 |     let trivial_empty = Regex::new("");
+LL |     let trivial_empty = Regex::new("");
    |                                    ^^
    |
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:71:36
+  --> $DIR/regex.rs:59:36
    |
-71 |     let trivial_empty = Regex::new("^");
+LL |     let trivial_empty = Regex::new("^");
    |                                    ^^^
    |
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:73:36
+  --> $DIR/regex.rs:61:36
    |
-73 |     let trivial_empty = Regex::new("^$");
+LL |     let trivial_empty = Regex::new("^$");
    |                                    ^^^^
    |
    = help: consider using `str::is_empty`
 
 error: trivial regex
-  --> $DIR/regex.rs:75:44
+  --> $DIR/regex.rs:63:44
    |
-75 |     let binary_trivial_empty = BRegex::new("^$");
+LL |     let binary_trivial_empty = BRegex::new("^$");
    |                                            ^^^^
    |
    = help: consider using `str::is_empty`
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
new file mode 100644 (file)
index 0000000..b1846a1
--- /dev/null
@@ -0,0 +1,14 @@
+#![allow(stutter)]
+#![warn(clippy::cyclomatic_complexity)]
+
+#[warn(clippy::stutter)]
+fn main() {}
+
+#[warn(clippy::new_without_default_derive)]
+struct Foo;
+
+impl Foo {
+    fn new() -> Self {
+        Foo
+    }
+}
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
new file mode 100644 (file)
index 0000000..ac850b6
--- /dev/null
@@ -0,0 +1,42 @@
+error: unknown lint: `stutter`
+  --> $DIR/rename.rs:1:10
+   |
+LL | #![allow(stutter)]
+   |          ^^^^^^^
+   |
+   = note: `-D unknown-lints` implied by `-D warnings`
+
+error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
+  --> $DIR/rename.rs:2:9
+   |
+LL | #![warn(clippy::cyclomatic_complexity)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+  --> $DIR/rename.rs:4:8
+   |
+LL | #[warn(clippy::stutter)]
+   |        ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+  --> $DIR/rename.rs:7:8
+   |
+LL | #[warn(clippy::new_without_default_derive)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+
+error: unknown lint: `stutter`
+  --> $DIR/rename.rs:1:10
+   |
+LL | #![allow(stutter)]
+   |          ^^^^^^^
+
+error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
+  --> $DIR/rename.rs:2:9
+   |
+LL | #![warn(clippy::cyclomatic_complexity)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/renamed_builtin_attr.rs b/tests/ui/renamed_builtin_attr.rs
new file mode 100644 (file)
index 0000000..fdb4253
--- /dev/null
@@ -0,0 +1,2 @@
+#[clippy::cyclomatic_complexity = "1"]
+fn main() {}
diff --git a/tests/ui/renamed_builtin_attr.stderr b/tests/ui/renamed_builtin_attr.stderr
new file mode 100644 (file)
index 0000000..cf6cccd
--- /dev/null
@@ -0,0 +1,8 @@
+error: Usage of deprecated attribute
+  --> $DIR/renamed_builtin_attr.rs:1:11
+   |
+LL | #[clippy::cyclomatic_complexity = "1"]
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/replace_consts.fixed b/tests/ui/replace_consts.fixed
new file mode 100644 (file)
index 0000000..2c125f9
--- /dev/null
@@ -0,0 +1,88 @@
+// run-rustfix
+#![feature(integer_atomics)]
+#![allow(unused_variables, clippy::blacklisted_name)]
+#![deny(clippy::replace_consts)]
+
+use std::sync::atomic::*;
+use std::sync::{Once, ONCE_INIT};
+
+#[rustfmt::skip]
+fn bad() {
+    // Once
+    { let foo = ONCE_INIT; };
+    // Min
+    { let foo = isize::min_value(); };
+    { let foo = i8::min_value(); };
+    { let foo = i16::min_value(); };
+    { let foo = i32::min_value(); };
+    { let foo = i64::min_value(); };
+    { let foo = i128::min_value(); };
+    { let foo = usize::min_value(); };
+    { let foo = u8::min_value(); };
+    { let foo = u16::min_value(); };
+    { let foo = u32::min_value(); };
+    { let foo = u64::min_value(); };
+    { let foo = u128::min_value(); };
+    // Max
+    { let foo = isize::max_value(); };
+    { let foo = i8::max_value(); };
+    { let foo = i16::max_value(); };
+    { let foo = i32::max_value(); };
+    { let foo = i64::max_value(); };
+    { let foo = i128::max_value(); };
+    { let foo = usize::max_value(); };
+    { let foo = u8::max_value(); };
+    { let foo = u16::max_value(); };
+    { let foo = u32::max_value(); };
+    { let foo = u64::max_value(); };
+    { let foo = u128::max_value(); };
+}
+
+#[rustfmt::skip]
+fn good() {
+    // Once
+    { let foo = Once::new(); };
+    // Atomic
+    { let foo = AtomicBool::new(false); };
+    { let foo = AtomicIsize::new(0); };
+    { let foo = AtomicI8::new(0); };
+    { let foo = AtomicI16::new(0); };
+    { let foo = AtomicI32::new(0); };
+    { let foo = AtomicI64::new(0); };
+    { let foo = AtomicUsize::new(0); };
+    { let foo = AtomicU8::new(0); };
+    { let foo = AtomicU16::new(0); };
+    { let foo = AtomicU32::new(0); };
+    { let foo = AtomicU64::new(0); };
+    // Min
+    { let foo = isize::min_value(); };
+    { let foo = i8::min_value(); };
+    { let foo = i16::min_value(); };
+    { let foo = i32::min_value(); };
+    { let foo = i64::min_value(); };
+    { let foo = i128::min_value(); };
+    { let foo = usize::min_value(); };
+    { let foo = u8::min_value(); };
+    { let foo = u16::min_value(); };
+    { let foo = u32::min_value(); };
+    { let foo = u64::min_value(); };
+    { let foo = u128::min_value(); };
+    // Max
+    { let foo = isize::max_value(); };
+    { let foo = i8::max_value(); };
+    { let foo = i16::max_value(); };
+    { let foo = i32::max_value(); };
+    { let foo = i64::max_value(); };
+    { let foo = i128::max_value(); };
+    { let foo = usize::max_value(); };
+    { let foo = u8::max_value(); };
+    { let foo = u16::max_value(); };
+    { let foo = u32::max_value(); };
+    { let foo = u64::max_value(); };
+    { let foo = u128::max_value(); };
+}
+
+fn main() {
+    bad();
+    good();
+}
index 71d4ea98e07abeef6ec2e0c78474464270525013..3c7d8d07ed6f6dd7256fe9d4551bc5ead7929954 100644 (file)
@@ -1,25 +1,15 @@
+// run-rustfix
 #![feature(integer_atomics)]
-#![allow(blacklisted_name)]
-#![deny(replace_consts)]
+#![allow(unused_variables, clippy::blacklisted_name)]
+#![deny(clippy::replace_consts)]
 
 use std::sync::atomic::*;
-use std::sync::{ONCE_INIT, Once};
+use std::sync::{Once, ONCE_INIT};
 
+#[rustfmt::skip]
 fn bad() {
     // Once
     { let foo = ONCE_INIT; };
-    // Atomic
-    { let foo = ATOMIC_BOOL_INIT; };
-    { let foo = ATOMIC_ISIZE_INIT; };
-    { let foo = ATOMIC_I8_INIT; };
-    { let foo = ATOMIC_I16_INIT; };
-    { let foo = ATOMIC_I32_INIT; };
-    { let foo = ATOMIC_I64_INIT; };
-    { let foo = ATOMIC_USIZE_INIT; };
-    { let foo = ATOMIC_U8_INIT; };
-    { let foo = ATOMIC_U16_INIT; };
-    { let foo = ATOMIC_U32_INIT; };
-    { let foo = ATOMIC_U64_INIT; };
     // Min
     { let foo = std::isize::MIN; };
     { let foo = std::i8::MIN; };
@@ -48,6 +38,7 @@ fn bad() {
     { let foo = std::u128::MAX; };
 }
 
+#[rustfmt::skip]
 fn good() {
     // Once
     { let foo = Once::new(); };
index 0a9d5f4ab7556544fcb5931c148953e98b26e163..be0d00726237fb72f91bbdfafac9c391d618e089 100644 (file)
-error: using `ATOMIC_BOOL_INIT`
-  --> $DIR/replace_consts.rs:12:17
-   |
-12 |     { let foo = ATOMIC_BOOL_INIT; };
-   |                 ^^^^^^^^^^^^^^^^ help: try this: `AtomicBool::new(false)`
-   |
-note: lint level defined here
-  --> $DIR/replace_consts.rs:3:9
-   |
-3  | #![deny(replace_consts)]
-   |         ^^^^^^^^^^^^^^
-
-error: using `ATOMIC_ISIZE_INIT`
-  --> $DIR/replace_consts.rs:13:17
-   |
-13 |     { let foo = ATOMIC_ISIZE_INIT; };
-   |                 ^^^^^^^^^^^^^^^^^ help: try this: `AtomicIsize::new(0)`
-
-error: using `ATOMIC_I8_INIT`
+error: using `MIN`
   --> $DIR/replace_consts.rs:14:17
    |
-14 |     { let foo = ATOMIC_I8_INIT; };
-   |                 ^^^^^^^^^^^^^^ help: try this: `AtomicI8::new(0)`
-
-error: using `ATOMIC_I16_INIT`
-  --> $DIR/replace_consts.rs:15:17
-   |
-15 |     { let foo = ATOMIC_I16_INIT; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `AtomicI16::new(0)`
-
-error: using `ATOMIC_I32_INIT`
-  --> $DIR/replace_consts.rs:16:17
-   |
-16 |     { let foo = ATOMIC_I32_INIT; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `AtomicI32::new(0)`
-
-error: using `ATOMIC_I64_INIT`
-  --> $DIR/replace_consts.rs:17:17
-   |
-17 |     { let foo = ATOMIC_I64_INIT; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `AtomicI64::new(0)`
-
-error: using `ATOMIC_USIZE_INIT`
-  --> $DIR/replace_consts.rs:18:17
-   |
-18 |     { let foo = ATOMIC_USIZE_INIT; };
-   |                 ^^^^^^^^^^^^^^^^^ help: try this: `AtomicUsize::new(0)`
-
-error: using `ATOMIC_U8_INIT`
-  --> $DIR/replace_consts.rs:19:17
-   |
-19 |     { let foo = ATOMIC_U8_INIT; };
-   |                 ^^^^^^^^^^^^^^ help: try this: `AtomicU8::new(0)`
-
-error: using `ATOMIC_U16_INIT`
-  --> $DIR/replace_consts.rs:20:17
-   |
-20 |     { let foo = ATOMIC_U16_INIT; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `AtomicU16::new(0)`
-
-error: using `ATOMIC_U32_INIT`
-  --> $DIR/replace_consts.rs:21:17
-   |
-21 |     { let foo = ATOMIC_U32_INIT; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `AtomicU32::new(0)`
-
-error: using `ATOMIC_U64_INIT`
-  --> $DIR/replace_consts.rs:22:17
+LL |     { let foo = std::isize::MIN; };
+   |                 ^^^^^^^^^^^^^^^ help: try this: `isize::min_value()`
    |
-22 |     { let foo = ATOMIC_U64_INIT; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `AtomicU64::new(0)`
-
-error: using `MIN`
-  --> $DIR/replace_consts.rs:24:17
+note: lint level defined here
+  --> $DIR/replace_consts.rs:4:9
    |
-24 |     { let foo = std::isize::MIN; };
-   |                 ^^^^^^^^^^^^^^^ help: try this: `isize::min_value()`
+LL | #![deny(clippy::replace_consts)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:25:17
+  --> $DIR/replace_consts.rs:15:17
    |
-25 |     { let foo = std::i8::MIN; };
+LL |     { let foo = std::i8::MIN; };
    |                 ^^^^^^^^^^^^ help: try this: `i8::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:26:17
+  --> $DIR/replace_consts.rs:16:17
    |
-26 |     { let foo = std::i16::MIN; };
+LL |     { let foo = std::i16::MIN; };
    |                 ^^^^^^^^^^^^^ help: try this: `i16::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:27:17
+  --> $DIR/replace_consts.rs:17:17
    |
-27 |     { let foo = std::i32::MIN; };
+LL |     { let foo = std::i32::MIN; };
    |                 ^^^^^^^^^^^^^ help: try this: `i32::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:28:17
+  --> $DIR/replace_consts.rs:18:17
    |
-28 |     { let foo = std::i64::MIN; };
+LL |     { let foo = std::i64::MIN; };
    |                 ^^^^^^^^^^^^^ help: try this: `i64::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:29:17
+  --> $DIR/replace_consts.rs:19:17
    |
-29 |     { let foo = std::i128::MIN; };
+LL |     { let foo = std::i128::MIN; };
    |                 ^^^^^^^^^^^^^^ help: try this: `i128::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:30:17
+  --> $DIR/replace_consts.rs:20:17
    |
-30 |     { let foo = std::usize::MIN; };
+LL |     { let foo = std::usize::MIN; };
    |                 ^^^^^^^^^^^^^^^ help: try this: `usize::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:31:17
+  --> $DIR/replace_consts.rs:21:17
    |
-31 |     { let foo = std::u8::MIN; };
+LL |     { let foo = std::u8::MIN; };
    |                 ^^^^^^^^^^^^ help: try this: `u8::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:32:17
+  --> $DIR/replace_consts.rs:22:17
    |
-32 |     { let foo = std::u16::MIN; };
+LL |     { let foo = std::u16::MIN; };
    |                 ^^^^^^^^^^^^^ help: try this: `u16::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:33:17
+  --> $DIR/replace_consts.rs:23:17
    |
-33 |     { let foo = std::u32::MIN; };
+LL |     { let foo = std::u32::MIN; };
    |                 ^^^^^^^^^^^^^ help: try this: `u32::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:34:17
+  --> $DIR/replace_consts.rs:24:17
    |
-34 |     { let foo = std::u64::MIN; };
+LL |     { let foo = std::u64::MIN; };
    |                 ^^^^^^^^^^^^^ help: try this: `u64::min_value()`
 
 error: using `MIN`
-  --> $DIR/replace_consts.rs:35:17
+  --> $DIR/replace_consts.rs:25:17
    |
-35 |     { let foo = std::u128::MIN; };
+LL |     { let foo = std::u128::MIN; };
    |                 ^^^^^^^^^^^^^^ help: try this: `u128::min_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:37:17
+  --> $DIR/replace_consts.rs:27:17
    |
-37 |     { let foo = std::isize::MAX; };
+LL |     { let foo = std::isize::MAX; };
    |                 ^^^^^^^^^^^^^^^ help: try this: `isize::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:38:17
+  --> $DIR/replace_consts.rs:28:17
    |
-38 |     { let foo = std::i8::MAX; };
+LL |     { let foo = std::i8::MAX; };
    |                 ^^^^^^^^^^^^ help: try this: `i8::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:39:17
+  --> $DIR/replace_consts.rs:29:17
    |
-39 |     { let foo = std::i16::MAX; };
+LL |     { let foo = std::i16::MAX; };
    |                 ^^^^^^^^^^^^^ help: try this: `i16::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:40:17
+  --> $DIR/replace_consts.rs:30:17
    |
-40 |     { let foo = std::i32::MAX; };
+LL |     { let foo = std::i32::MAX; };
    |                 ^^^^^^^^^^^^^ help: try this: `i32::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:41:17
+  --> $DIR/replace_consts.rs:31:17
    |
-41 |     { let foo = std::i64::MAX; };
+LL |     { let foo = std::i64::MAX; };
    |                 ^^^^^^^^^^^^^ help: try this: `i64::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:42:17
+  --> $DIR/replace_consts.rs:32:17
    |
-42 |     { let foo = std::i128::MAX; };
+LL |     { let foo = std::i128::MAX; };
    |                 ^^^^^^^^^^^^^^ help: try this: `i128::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:43:17
+  --> $DIR/replace_consts.rs:33:17
    |
-43 |     { let foo = std::usize::MAX; };
+LL |     { let foo = std::usize::MAX; };
    |                 ^^^^^^^^^^^^^^^ help: try this: `usize::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:44:17
+  --> $DIR/replace_consts.rs:34:17
    |
-44 |     { let foo = std::u8::MAX; };
+LL |     { let foo = std::u8::MAX; };
    |                 ^^^^^^^^^^^^ help: try this: `u8::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:45:17
+  --> $DIR/replace_consts.rs:35:17
    |
-45 |     { let foo = std::u16::MAX; };
+LL |     { let foo = std::u16::MAX; };
    |                 ^^^^^^^^^^^^^ help: try this: `u16::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:46:17
+  --> $DIR/replace_consts.rs:36:17
    |
-46 |     { let foo = std::u32::MAX; };
+LL |     { let foo = std::u32::MAX; };
    |                 ^^^^^^^^^^^^^ help: try this: `u32::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:47:17
+  --> $DIR/replace_consts.rs:37:17
    |
-47 |     { let foo = std::u64::MAX; };
+LL |     { let foo = std::u64::MAX; };
    |                 ^^^^^^^^^^^^^ help: try this: `u64::max_value()`
 
 error: using `MAX`
-  --> $DIR/replace_consts.rs:48:17
+  --> $DIR/replace_consts.rs:38:17
    |
-48 |     { let foo = std::u128::MAX; };
+LL |     { let foo = std::u128::MAX; };
    |                 ^^^^^^^^^^^^^^ help: try this: `u128::max_value()`
 
-error: aborting due to 35 previous errors
+error: aborting due to 24 previous errors
 
index dd163439d7843f18f62d24c3216b719b91992e38..a8e891d8db024636560b72709bd72ad24569efc3 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(never_type)]
-#![warn(result_map_unit_fn)]
+#![warn(clippy::result_map_unit_fn)]
 #![allow(unused)]
 
 fn do_nothing<T>(_: T) {}
@@ -24,11 +24,12 @@ fn do_result_plus_one(self: &Self, value: usize) -> usize {
     }
 }
 
+#[rustfmt::skip]
 fn result_map_unit_fn() {
     let x = HasResult { field: Ok(10) };
 
     x.field.map(plus_one);
-    let _ : Result<(), usize> = x.field.map(do_nothing);
+    let _: Result<(), usize> = x.field.map(do_nothing);
 
     x.field.map(do_nothing);
 
@@ -38,7 +39,7 @@ fn result_map_unit_fn() {
 
     let captured = 10;
     if let Ok(value) = x.field { do_nothing(value + captured) };
-    let _ : Result<(), usize> = x.field.map(|value| do_nothing(value + captured));
+    let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured));
 
     x.field.map(|value| x.do_result_nothing(value + captured));
 
@@ -98,6 +99,4 @@ fn result_map_unit_fn() {
     y.map(do_nothing);
 }
 
-fn main() {
-}
-
+fn main() {}
index 9ec24a7e97b8fe7221e3e04833f10a2af0b94661..9f9025152e2438b740b1868f4abfc2cbf8a90b93 100644 (file)
 error: called `map(f)` on an Result value where `f` is a unit function
-  --> $DIR/result_map_unit_fn.rs:33:5
+  --> $DIR/result_map_unit_fn.rs:34:5
    |
-33 |     x.field.map(do_nothing);
+LL |     x.field.map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { do_nothing(...) }`
    |
-   = note: `-D result-map-unit-fn` implied by `-D warnings`
+   = note: `-D clippy::result-map-unit-fn` implied by `-D warnings`
 
 error: called `map(f)` on an Result value where `f` is a unit function
-  --> $DIR/result_map_unit_fn.rs:35:5
+  --> $DIR/result_map_unit_fn.rs:36:5
    |
-35 |     x.field.map(do_nothing);
+LL |     x.field.map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { do_nothing(...) }`
 
 error: called `map(f)` on an Result value where `f` is a unit function
-  --> $DIR/result_map_unit_fn.rs:37:5
+  --> $DIR/result_map_unit_fn.rs:38:5
    |
-37 |     x.field.map(diverge);
+LL |     x.field.map(diverge);
    |     ^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(x_field) = x.field { diverge(...) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:43:5
+  --> $DIR/result_map_unit_fn.rs:44:5
    |
-43 |     x.field.map(|value| x.do_result_nothing(value + captured));
+LL |     x.field.map(|value| x.do_result_nothing(value + captured));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:45:5
+  --> $DIR/result_map_unit_fn.rs:46:5
    |
-45 |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
+LL |     x.field.map(|value| { x.do_result_plus_one(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:48:5
+  --> $DIR/result_map_unit_fn.rs:49:5
    |
-48 |     x.field.map(|value| do_nothing(value + captured));
+LL |     x.field.map(|value| do_nothing(value + captured));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:50:5
+  --> $DIR/result_map_unit_fn.rs:51:5
    |
-50 |     x.field.map(|value| { do_nothing(value + captured) });
+LL |     x.field.map(|value| { do_nothing(value + captured) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:52:5
+  --> $DIR/result_map_unit_fn.rs:53:5
    |
-52 |     x.field.map(|value| { do_nothing(value + captured); });
+LL |     x.field.map(|value| { do_nothing(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:54:5
+  --> $DIR/result_map_unit_fn.rs:55:5
    |
-54 |     x.field.map(|value| { { do_nothing(value + captured); } });
+LL |     x.field.map(|value| { { do_nothing(value + captured); } });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:57:5
+  --> $DIR/result_map_unit_fn.rs:58:5
    |
-57 |     x.field.map(|value| diverge(value + captured));
+LL |     x.field.map(|value| diverge(value + captured));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:59:5
+  --> $DIR/result_map_unit_fn.rs:60:5
    |
-59 |     x.field.map(|value| { diverge(value + captured) });
+LL |     x.field.map(|value| { diverge(value + captured) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:61:5
+  --> $DIR/result_map_unit_fn.rs:62:5
    |
-61 |     x.field.map(|value| { diverge(value + captured); });
+LL |     x.field.map(|value| { diverge(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:63:5
+  --> $DIR/result_map_unit_fn.rs:64:5
    |
-63 |     x.field.map(|value| { { diverge(value + captured); } });
+LL |     x.field.map(|value| { { diverge(value + captured); } });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { diverge(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:68:5
+  --> $DIR/result_map_unit_fn.rs:69:5
    |
-68 |     x.field.map(|value| { let y = plus_one(value + captured); });
+LL |     x.field.map(|value| { let y = plus_one(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:70:5
+  --> $DIR/result_map_unit_fn.rs:71:5
    |
-70 |     x.field.map(|value| { plus_one(value + captured); });
+LL |     x.field.map(|value| { plus_one(value + captured); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:72:5
+  --> $DIR/result_map_unit_fn.rs:73:5
    |
-72 |     x.field.map(|value| { { plus_one(value + captured); } });
+LL |     x.field.map(|value| { { plus_one(value + captured); } });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:75:5
+  --> $DIR/result_map_unit_fn.rs:76:5
    |
-75 |     x.field.map(|ref value| { do_nothing(value + captured) });
+LL |     x.field.map(|ref value| { do_nothing(value + captured) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:78:5
+  --> $DIR/result_map_unit_fn.rs:79:5
    |
-78 |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:80:5
+  --> $DIR/result_map_unit_fn.rs:81:5
    |
-80 |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
+LL |     x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:84:5
+  --> $DIR/result_map_unit_fn.rs:85:5
    |
-84 |        x.field.map(|value| {
+LL |        x.field.map(|value| {
    |   _____^
    |  |_____|
    | ||
-85 | ||         do_nothing(value);
-86 | ||         do_nothing(value)
-87 | ||     });
+LL | ||         do_nothing(value);
+LL | ||         do_nothing(value)
+LL | ||     });
    | ||______^- help: try this: `if let Ok(value) = x.field { ... }`
    | |_______|
    | 
 
 error: called `map(f)` on an Result value where `f` is a unit closure
-  --> $DIR/result_map_unit_fn.rs:88:5
+  --> $DIR/result_map_unit_fn.rs:89:5
    |
-88 |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
+LL |     x.field.map(|value| { do_nothing(value); do_nothing(value); });
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(value) = x.field { ... }`
 
 error: called `map(f)` on an Result value where `f` is a unit function
-  --> $DIR/result_map_unit_fn.rs:92:5
+  --> $DIR/result_map_unit_fn.rs:93:5
    |
-92 |     "12".parse::<i32>().map(diverge);
+LL |     "12".parse::<i32>().map(diverge);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(_) = "12".parse::<i32>() { diverge(...) }`
 
 error: called `map(f)` on an Result value where `f` is a unit function
-  --> $DIR/result_map_unit_fn.rs:98:5
+  --> $DIR/result_map_unit_fn.rs:99:5
    |
-98 |     y.map(do_nothing);
+LL |     y.map(do_nothing);
    |     ^^^^^^^^^^^^^^^^^-
    |     |
    |     help: try this: `if let Ok(_y) = y { do_nothing(...) }`
diff --git a/tests/ui/result_map_unwrap_or_else.rs b/tests/ui/result_map_unwrap_or_else.rs
new file mode 100644 (file)
index 0000000..40751bf
--- /dev/null
@@ -0,0 +1,23 @@
+// aux-build:option_helpers.rs
+
+//! Checks implementation of `RESULT_MAP_UNWRAP_OR_ELSE`
+
+#![warn(clippy::result_map_unwrap_or_else)]
+
+#[macro_use]
+extern crate option_helpers;
+
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // Check RESULT_MAP_UNWRAP_OR_ELSE
+    // single line case
+    let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
+                                                      // multi line cases
+    let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+    let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+    // macro case
+    let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint
+}
+
+fn main() {}
diff --git a/tests/ui/result_map_unwrap_or_else.stderr b/tests/ui/result_map_unwrap_or_else.stderr
new file mode 100644 (file)
index 0000000..7674b91
--- /dev/null
@@ -0,0 +1,27 @@
+error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead
+  --> $DIR/result_map_unwrap_or_else.rs:15:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::result-map-unwrap-or-else` implied by `-D warnings`
+   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)`
+
+error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead
+  --> $DIR/result_map_unwrap_or_else.rs:17:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)`
+
+error: called `map(f).unwrap_or_else(g)` on a Result value. This can be done more directly by calling `ok().map_or_else(g, f)` instead
+  --> $DIR/result_map_unwrap_or_else.rs:18:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `ok().map_or_else(|e| 0, |x| x + 1)`
+
+error: aborting due to 3 previous errors
+
index 792ebc9b0ea18b4ee232f2e9270559bb85e48b8f..5843344eba89a32f83bce805f88d99e4027653d5 100644 (file)
@@ -1,6 +1,4 @@
-
-
-#![warn(serde_api_misuse)]
+#![warn(clippy::serde_api_misuse)]
 #![allow(dead_code)]
 
 extern crate serde;
@@ -15,13 +13,15 @@ fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
     }
 
     fn visit_str<E>(self, _v: &str) -> Result<Self::Value, E>
-        where E: serde::de::Error,
+    where
+        E: serde::de::Error,
     {
         unimplemented!()
     }
 
     fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
-        where E: serde::de::Error,
+    where
+        E: serde::de::Error,
     {
         unimplemented!()
     }
@@ -37,11 +37,11 @@ fn expecting(&self, _: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
     }
 
     fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
-        where E: serde::de::Error,
+    where
+        E: serde::de::Error,
     {
         unimplemented!()
     }
 }
 
-fn main() {
-}
+fn main() {}
index 58667e0f820b73eec81d7465c9db83dc8927f2ee..760c9c9908a6f06733c6e0db7a3421b94462cfcb 100644 (file)
@@ -1,14 +1,15 @@
 error: you should not implement `visit_string` without also implementing `visit_str`
   --> $DIR/serde.rs:39:5
    |
-39 | /     fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
-40 | |         where E: serde::de::Error,
-41 | |     {
-42 | |         unimplemented!()
-43 | |     }
+LL | /     fn visit_string<E>(self, _v: String) -> Result<Self::Value, E>
+LL | |     where
+LL | |         E: serde::de::Error,
+LL | |     {
+LL | |         unimplemented!()
+LL | |     }
    | |_____^
    |
-   = note: `-D serde-api-misuse` implied by `-D warnings`
+   = note: `-D clippy::serde-api-misuse` implied by `-D warnings`
 
 error: aborting due to previous error
 
index 79c1030d48be8fac16a2899802e9b5d70600882a..a9c77aca66f577f0e5058fc35ef8381d602864b2 100644 (file)
@@ -1,12 +1,19 @@
+#![warn(
+    clippy::all,
+    clippy::pedantic,
+    clippy::shadow_same,
+    clippy::shadow_reuse,
+    clippy::shadow_unrelated
+)]
+#![allow(unused_parens, unused_variables, clippy::missing_docs_in_private_items)]
+
+fn id<T>(x: T) -> T {
+    x
+}
 
-
-
-#![warn(clippy, clippy_pedantic, shadow_same, shadow_reuse, shadow_unrelated)]
-#![allow(unused_parens, unused_variables, missing_docs_in_private_items)]
-
-fn id<T>(x: T) -> T { x }
-
-fn first(x: (isize, isize)) -> isize { x.0 }
+fn first(x: (isize, isize)) -> isize {
+    x.0
+}
 
 fn main() {
     let mut x = 1;
@@ -25,7 +32,9 @@ fn main() {
 
     let o = Some(1_u8);
 
-    if let Some(p) = o { assert_eq!(1, p); }
+    if let Some(p) = o {
+        assert_eq!(1, p);
+    }
     match o {
         Some(p) => p, // no error, because the p above is in its own scope
         None => 0,
index 0eb5e5b2a2b30d49a42810abd9d1c51675778318..ada8b07d69b757a3c5d2633a879e27ca4bb91e02 100644 (file)
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:13:5
+  --> $DIR/shadow.rs:20:5
    |
-13 |     let x = &mut x;
+LL |     let x = &mut x;
    |     ^^^^^^^^^^^^^^^
    |
-   = note: `-D shadow-same` implied by `-D warnings`
+   = note: `-D clippy::shadow-same` implied by `-D warnings`
 note: previous binding is here
-  --> $DIR/shadow.rs:12:13
+  --> $DIR/shadow.rs:19:13
    |
-12 |     let mut x = 1;
+LL |     let mut x = 1;
    |             ^
 
 error: `x` is shadowed by itself in `{ x }`
-  --> $DIR/shadow.rs:14:5
+  --> $DIR/shadow.rs:21:5
    |
-14 |     let x = { x };
+LL |     let x = { x };
    |     ^^^^^^^^^^^^^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:20:9
    |
-13 |     let x = &mut x;
+LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed by itself in `(&*x)`
-  --> $DIR/shadow.rs:15:5
+  --> $DIR/shadow.rs:22:5
    |
-15 |     let x = (&*x);
+LL |     let x = (&*x);
    |     ^^^^^^^^^^^^^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:14:9
+  --> $DIR/shadow.rs:21:9
    |
-14 |     let x = { x };
+LL |     let x = { x };
    |         ^
 
 error: `x` is shadowed by `{ *x + 1 }` which reuses the original value
-  --> $DIR/shadow.rs:16:9
+  --> $DIR/shadow.rs:23:9
    |
-16 |     let x = { *x + 1 };
+LL |     let x = { *x + 1 };
    |         ^
    |
-   = note: `-D shadow-reuse` implied by `-D warnings`
+   = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 note: initialization happens here
-  --> $DIR/shadow.rs:16:13
+  --> $DIR/shadow.rs:23:13
    |
-16 |     let x = { *x + 1 };
+LL |     let x = { *x + 1 };
    |             ^^^^^^^^^^
 note: previous binding is here
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:22:9
    |
-15 |     let x = (&*x);
+LL |     let x = (&*x);
    |         ^
 
 error: `x` is shadowed by `id(x)` which reuses the original value
-  --> $DIR/shadow.rs:17:9
+  --> $DIR/shadow.rs:24:9
    |
-17 |     let x = id(x);
+LL |     let x = id(x);
    |         ^
    |
 note: initialization happens here
-  --> $DIR/shadow.rs:17:13
+  --> $DIR/shadow.rs:24:13
    |
-17 |     let x = id(x);
+LL |     let x = id(x);
    |             ^^^^^
 note: previous binding is here
-  --> $DIR/shadow.rs:16:9
+  --> $DIR/shadow.rs:23:9
    |
-16 |     let x = { *x + 1 };
+LL |     let x = { *x + 1 };
    |         ^
 
 error: `x` is shadowed by `(1, x)` which reuses the original value
-  --> $DIR/shadow.rs:18:9
+  --> $DIR/shadow.rs:25:9
    |
-18 |     let x = (1, x);
+LL |     let x = (1, x);
    |         ^
    |
 note: initialization happens here
-  --> $DIR/shadow.rs:18:13
+  --> $DIR/shadow.rs:25:13
    |
-18 |     let x = (1, x);
+LL |     let x = (1, x);
    |             ^^^^^^
 note: previous binding is here
-  --> $DIR/shadow.rs:17:9
+  --> $DIR/shadow.rs:24:9
    |
-17 |     let x = id(x);
+LL |     let x = id(x);
    |         ^
 
 error: `x` is shadowed by `first(x)` which reuses the original value
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:26:9
    |
-19 |     let x = first(x);
+LL |     let x = first(x);
    |         ^
    |
 note: initialization happens here
-  --> $DIR/shadow.rs:19:13
+  --> $DIR/shadow.rs:26:13
    |
-19 |     let x = first(x);
+LL |     let x = first(x);
    |             ^^^^^^^^
 note: previous binding is here
-  --> $DIR/shadow.rs:18:9
+  --> $DIR/shadow.rs:25:9
    |
-18 |     let x = (1, x);
+LL |     let x = (1, x);
    |         ^
 
 error: `x` is shadowed by `y`
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:28:9
    |
-21 |     let x = y;
+LL |     let x = y;
    |         ^
    |
-   = note: `-D shadow-unrelated` implied by `-D warnings`
+   = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 note: initialization happens here
-  --> $DIR/shadow.rs:21:13
+  --> $DIR/shadow.rs:28:13
    |
-21 |     let x = y;
+LL |     let x = y;
    |             ^
 note: previous binding is here
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:26:9
    |
-19 |     let x = first(x);
+LL |     let x = first(x);
    |         ^
 
 error: `x` shadows a previous declaration
-  --> $DIR/shadow.rs:23:5
+  --> $DIR/shadow.rs:30:5
    |
-23 |     let x;
+LL |     let x;
    |     ^^^^^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:28:9
    |
-21 |     let x = y;
+LL |     let x = y;
    |         ^
 
 error: aborting due to 9 previous errors
index 0f5773623be347629c410ec615b109e1a9a72e54..84e736fe080f7b61d984f36a49a3d1e2ad37ef02 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![warn(short_circuit_statement)]
+#![warn(clippy::short_circuit_statement)]
 
 fn main() {
     f() && g();
index 7697cbd1c64c032c249536f6bb9342527967ed46..a526766f69896ecfab607b06cc4b73fa767266c3 100644 (file)
@@ -1,22 +1,22 @@
 error: boolean short circuit operator in statement may be clearer using an explicit test
--> $DIR/short_circuit_statement.rs:7:5
-  |
-7 |     f() && g();
-  |     ^^^^^^^^^^^ help: replace it with: `if f() { g(); }`
-  |
-  = note: `-D short-circuit-statement` implied by `-D warnings`
 --> $DIR/short_circuit_statement.rs:4:5
+   |
+LL |     f() && g();
+   |     ^^^^^^^^^^^ help: replace it with: `if f() { g(); }`
+   |
+   = note: `-D clippy::short-circuit-statement` implied by `-D warnings`
 
 error: boolean short circuit operator in statement may be clearer using an explicit test
--> $DIR/short_circuit_statement.rs:8:5
-  |
-8 |     f() || g();
-  |     ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }`
 --> $DIR/short_circuit_statement.rs:5:5
+   |
+LL |     f() || g();
+   |     ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }`
 
 error: boolean short circuit operator in statement may be clearer using an explicit test
--> $DIR/short_circuit_statement.rs:9:5
-  |
-9 |     1 == 2 || g();
-  |     ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }`
 --> $DIR/short_circuit_statement.rs:6:5
+   |
+LL |     1 == 2 || g();
+   |     ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/similar_names.rs b/tests/ui/similar_names.rs
new file mode 100644 (file)
index 0000000..6796b15
--- /dev/null
@@ -0,0 +1,103 @@
+#![warn(clippy::similar_names)]
+#![allow(unused, clippy::println_empty_string)]
+
+struct Foo {
+    apple: i32,
+    bpple: i32,
+}
+
+fn main() {
+    let specter: i32;
+    let spectre: i32;
+
+    let apple: i32;
+
+    let bpple: i32;
+
+    let cpple: i32;
+
+    let a_bar: i32;
+    let b_bar: i32;
+    let c_bar: i32;
+
+    let items = [5];
+    for item in &items {
+        loop {}
+    }
+
+    let foo_x: i32;
+    let foo_y: i32;
+
+    let rhs: i32;
+    let lhs: i32;
+
+    let bla_rhs: i32;
+    let bla_lhs: i32;
+
+    let blubrhs: i32;
+    let blublhs: i32;
+
+    let blubx: i32;
+    let bluby: i32;
+
+    let cake: i32;
+    let cakes: i32;
+    let coke: i32;
+
+    match 5 {
+        cheese @ 1 => {},
+        rabbit => panic!(),
+    }
+    let cheese: i32;
+    match (42, 43) {
+        (cheese1, 1) => {},
+        (cheese2, 2) => panic!(),
+        _ => println!(""),
+    }
+    let ipv4: i32;
+    let ipv6: i32;
+    let abcd1: i32;
+    let abdc2: i32;
+    let xyz1abc: i32;
+    let xyz2abc: i32;
+    let xyzeabc: i32;
+
+    let parser: i32;
+    let parsed: i32;
+    let parsee: i32;
+
+    let setter: i32;
+    let getter: i32;
+    let tx1: i32;
+    let rx1: i32;
+    let tx_cake: i32;
+    let rx_cake: i32;
+}
+
+fn foo() {
+    let Foo { apple, bpple } = unimplemented!();
+    let Foo {
+        apple: spring,
+        bpple: sprang,
+    } = unimplemented!();
+}
+
+// false positive similar_names (#3057, #2651)
+// clippy claimed total_reg_src_size and total_size and
+// numb_reg_src_checkouts and total_bin_size were similar
+#[derive(Debug, Clone)]
+pub(crate) struct DirSizes {
+    pub(crate) total_size: u64,
+    pub(crate) numb_bins: u64,
+    pub(crate) total_bin_size: u64,
+    pub(crate) total_reg_size: u64,
+    pub(crate) total_git_db_size: u64,
+    pub(crate) total_git_repos_bare_size: u64,
+    pub(crate) numb_git_repos_bare_repos: u64,
+    pub(crate) numb_git_checkouts: u64,
+    pub(crate) total_git_chk_size: u64,
+    pub(crate) total_reg_cache_size: u64,
+    pub(crate) total_reg_src_size: u64,
+    pub(crate) numb_reg_cache_entries: u64,
+    pub(crate) numb_reg_src_checkouts: u64,
+}
diff --git a/tests/ui/similar_names.stderr b/tests/ui/similar_names.stderr
new file mode 100644 (file)
index 0000000..0256f12
--- /dev/null
@@ -0,0 +1,107 @@
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:15:9
+   |
+LL |     let bpple: i32;
+   |         ^^^^^
+   |
+   = note: `-D clippy::similar-names` implied by `-D warnings`
+note: existing binding defined here
+  --> $DIR/similar_names.rs:13:9
+   |
+LL |     let apple: i32;
+   |         ^^^^^
+help: separate the discriminating character by an underscore like: `b_pple`
+  --> $DIR/similar_names.rs:15:9
+   |
+LL |     let bpple: i32;
+   |         ^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:17:9
+   |
+LL |     let cpple: i32;
+   |         ^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:13:9
+   |
+LL |     let apple: i32;
+   |         ^^^^^
+help: separate the discriminating character by an underscore like: `c_pple`
+  --> $DIR/similar_names.rs:17:9
+   |
+LL |     let cpple: i32;
+   |         ^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:41:9
+   |
+LL |     let bluby: i32;
+   |         ^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:40:9
+   |
+LL |     let blubx: i32;
+   |         ^^^^^
+help: separate the discriminating character by an underscore like: `blub_y`
+  --> $DIR/similar_names.rs:41:9
+   |
+LL |     let bluby: i32;
+   |         ^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:45:9
+   |
+LL |     let coke: i32;
+   |         ^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:43:9
+   |
+LL |     let cake: i32;
+   |         ^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:63:9
+   |
+LL |     let xyzeabc: i32;
+   |         ^^^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:61:9
+   |
+LL |     let xyz1abc: i32;
+   |         ^^^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:67:9
+   |
+LL |     let parsee: i32;
+   |         ^^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:65:9
+   |
+LL |     let parser: i32;
+   |         ^^^^^^
+help: separate the discriminating character by an underscore like: `parse_e`
+  --> $DIR/similar_names.rs:67:9
+   |
+LL |     let parsee: i32;
+   |         ^^^^^^
+
+error: binding's name is too similar to existing binding
+  --> $DIR/similar_names.rs:81:16
+   |
+LL |         bpple: sprang,
+   |                ^^^^^^
+   |
+note: existing binding defined here
+  --> $DIR/similar_names.rs:80:16
+   |
+LL |         apple: spring,
+   |                ^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed
new file mode 100644 (file)
index 0000000..d5b6d81
--- /dev/null
@@ -0,0 +1,56 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+
+use std::collections::HashSet;
+
+fn main() {
+    let x = "foo";
+    x.split('x');
+    x.split("xx");
+    x.split('x');
+
+    let y = "x";
+    x.split(y);
+    // Not yet testing for multi-byte characters
+    // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern`
+    // should have done this but produced an ICE
+    //
+    // We may not want to suggest changing these anyway
+    // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984
+    x.split("ß");
+    x.split("ℝ");
+    x.split("💣");
+    // Can't use this lint for unicode code points which don't fit in a char
+    x.split("❤️");
+    x.contains('x');
+    x.starts_with('x');
+    x.ends_with('x');
+    x.find('x');
+    x.rfind('x');
+    x.rsplit('x');
+    x.split_terminator('x');
+    x.rsplit_terminator('x');
+    x.splitn(0, 'x');
+    x.rsplitn(0, 'x');
+    x.matches('x');
+    x.rmatches('x');
+    x.match_indices('x');
+    x.rmatch_indices('x');
+    x.trim_start_matches('x');
+    x.trim_end_matches('x');
+    // Make sure we escape characters correctly.
+    x.split('\n');
+    x.split('\'');
+    x.split('\'');
+
+    let h = HashSet::<String>::new();
+    h.contains("X"); // should not warn
+
+    x.replace(";", ",").split(','); // issue #2978
+    x.starts_with('\x03'); // issue #2996
+
+    // Issue #3204
+    const S: &str = "#";
+    x.find(S);
+}
index 73d00857415844d1301a3790d10b712fe17dc3e0..73f364854d0202f7c4afbc8889f848e895e71e1a 100644 (file)
@@ -1,3 +1,7 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+
 use std::collections::HashSet;
 
 fn main() {
@@ -9,11 +13,11 @@ fn main() {
     let y = "x";
     x.split(y);
     // Not yet testing for multi-byte characters
-    // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_single_char_pattern`
+    // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern`
     // should have done this but produced an ICE
     //
     // We may not want to suggest changing these anyway
-    // See: https://github.com/rust-lang-nursery/rust-clippy/issues/650#issuecomment-184328984
+    // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984
     x.split("ß");
     x.split("ℝ");
     x.split("💣");
@@ -33,13 +37,20 @@ fn main() {
     x.rmatches("x");
     x.match_indices("x");
     x.rmatch_indices("x");
-    x.trim_left_matches("x");
-    x.trim_right_matches("x");
+    x.trim_start_matches("x");
+    x.trim_end_matches("x");
     // Make sure we escape characters correctly.
     x.split("\n");
+    x.split("'");
+    x.split("\'");
 
     let h = HashSet::<String>::new();
     h.contains("X"); // should not warn
 
     x.replace(";", ",").split(","); // issue #2978
+    x.starts_with("\x03"); // issue #2996
+
+    // Issue #3204
+    const S: &str = "#";
+    x.find(S);
 }
index 1e7e9cf78cf13a4d3a32339751ff7465bcf7942c..d394c989c44c00575174dbcac026da0709370bc8 100644 (file)
 error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:5:13
-  |
-5 |     x.split("x");
-  |             ^^^ help: try using a char instead: `'x'`
-  |
-  = note: `-D single-char-pattern` implied by `-D warnings`
 --> $DIR/single_char_pattern.rs:9:13
+   |
+LL |     x.split("x");
+   |             ^^^ help: try using a char instead: `'x'`
+   |
+   = note: `-D clippy::single-char-pattern` implied by `-D warnings`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:22:16
+  --> $DIR/single_char_pattern.rs:26:16
    |
-22 |     x.contains("x");
+LL |     x.contains("x");
    |                ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:23:19
+  --> $DIR/single_char_pattern.rs:27:19
    |
-23 |     x.starts_with("x");
+LL |     x.starts_with("x");
    |                   ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:24:17
+  --> $DIR/single_char_pattern.rs:28:17
    |
-24 |     x.ends_with("x");
+LL |     x.ends_with("x");
    |                 ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:25:12
+  --> $DIR/single_char_pattern.rs:29:12
    |
-25 |     x.find("x");
+LL |     x.find("x");
    |            ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:26:13
+  --> $DIR/single_char_pattern.rs:30:13
    |
-26 |     x.rfind("x");
+LL |     x.rfind("x");
    |             ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:27:14
+  --> $DIR/single_char_pattern.rs:31:14
    |
-27 |     x.rsplit("x");
+LL |     x.rsplit("x");
    |              ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:28:24
+  --> $DIR/single_char_pattern.rs:32:24
    |
-28 |     x.split_terminator("x");
+LL |     x.split_terminator("x");
    |                        ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:29:25
+  --> $DIR/single_char_pattern.rs:33:25
    |
-29 |     x.rsplit_terminator("x");
+LL |     x.rsplit_terminator("x");
    |                         ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:30:17
+  --> $DIR/single_char_pattern.rs:34:17
    |
-30 |     x.splitn(0, "x");
+LL |     x.splitn(0, "x");
    |                 ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:31:18
+  --> $DIR/single_char_pattern.rs:35:18
    |
-31 |     x.rsplitn(0, "x");
+LL |     x.rsplitn(0, "x");
    |                  ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:32:15
+  --> $DIR/single_char_pattern.rs:36:15
    |
-32 |     x.matches("x");
+LL |     x.matches("x");
    |               ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:33:16
+  --> $DIR/single_char_pattern.rs:37:16
    |
-33 |     x.rmatches("x");
+LL |     x.rmatches("x");
    |                ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:34:21
+  --> $DIR/single_char_pattern.rs:38:21
    |
-34 |     x.match_indices("x");
+LL |     x.match_indices("x");
    |                     ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:35:22
+  --> $DIR/single_char_pattern.rs:39:22
    |
-35 |     x.rmatch_indices("x");
+LL |     x.rmatch_indices("x");
    |                      ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:36:25
+  --> $DIR/single_char_pattern.rs:40:26
    |
-36 |     x.trim_left_matches("x");
-   |                         ^^^ help: try using a char instead: `'x'`
+LL |     x.trim_start_matches("x");
+   |                          ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:37:26
+  --> $DIR/single_char_pattern.rs:41:24
    |
-37 |     x.trim_right_matches("x");
-   |                          ^^^ help: try using a char instead: `'x'`
+LL |     x.trim_end_matches("x");
+   |                        ^^^ help: try using a char instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:39:13
+  --> $DIR/single_char_pattern.rs:43:13
    |
-39 |     x.split("/n");
+LL |     x.split("/n");
    |             ^^^^ help: try using a char instead: `'/n'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:44:31
+  --> $DIR/single_char_pattern.rs:44:13
+   |
+LL |     x.split("'");
+   |             ^^^ help: try using a char instead: `'/''`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:45:13
+   |
+LL |     x.split("/'");
+   |             ^^^^ help: try using a char instead: `'/''`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:50:31
    |
-44 |     x.replace(";", ",").split(","); // issue #2978
+LL |     x.replace(";", ",").split(","); // issue #2978
    |                               ^^^ help: try using a char instead: `','`
 
-error: aborting due to 19 previous errors
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:51:19
+   |
+LL |     x.starts_with("/x03"); // issue #2996
+   |                   ^^^^^^ help: try using a char instead: `'/x03'`
+
+error: aborting due to 22 previous errors
 
index b064eed5711fe55f6c6ec0e8a7727657ea320ef0..99e88019cb89d3a28a21177eb250f5d5f4ba0752 100644 (file)
@@ -1,26 +1,36 @@
-#![warn(single_match)]
+#![warn(clippy::single_match)]
 
-fn dummy() {
-}
+fn dummy() {}
 
-fn single_match(){
+fn single_match() {
     let x = Some(1u8);
 
     match x {
-        Some(y) => { println!("{:?}", y); }
-        _ => ()
+        Some(y) => {
+            println!("{:?}", y);
+        },
+        _ => (),
     };
 
-    let z = (1u8,1u8);
+    let x = Some(1u8);
+    match x {
+        // Note the missing block braces.
+        // We suggest `if let Some(y) = x { .. }` because the macro
+        // is expanded before we can do anything.
+        Some(y) => println!("{:?}", y),
+        _ => (),
+    }
+
+    let z = (1u8, 1u8);
     match z {
         (2...3, 7...9) => dummy(),
-        _ => {}
+        _ => {},
     };
 
     // Not linted (pattern guards used)
     match x {
         Some(y) if y == 0 => println!("{:?}", y),
-        _ => ()
+        _ => (),
     }
 
     // Not linted (no block with statements in the single arm)
@@ -30,22 +40,25 @@ fn single_match(){
     }
 }
 
-enum Foo { Bar, Baz(u8) }
-use Foo::*;
+enum Foo {
+    Bar,
+    Baz(u8),
+}
 use std::borrow::Cow;
+use Foo::*;
 
 fn single_match_know_enum() {
     let x = Some(1u8);
-    let y : Result<_, i8> = Ok(1i8);
+    let y: Result<_, i8> = Ok(1i8);
 
     match x {
         Some(y) => dummy(),
-        None => ()
+        None => (),
     };
 
     match y {
         Ok(y) => dummy(),
-        Err(..) => ()
+        Err(..) => (),
     };
 
     let c = Cow::Borrowed("");
@@ -68,4 +81,4 @@ fn single_match_know_enum() {
     }
 }
 
-fn main() { }
+fn main() {}
index d77211bc12613b937dfda8d06688c919f34ef740..445f702d0cea98953d26c2ef9ca9f621188b3577 100644 (file)
@@ -1,49 +1,69 @@
 error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:9:5
+  --> $DIR/single_match.rs:8:5
    |
-9  | /     match x {
-10 | |         Some(y) => { println!("{:?}", y); }
-11 | |         _ => ()
-12 | |     };
-   | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y); }`
+LL | /     match x {
+LL | |         Some(y) => {
+LL | |             println!("{:?}", y);
+LL | |         },
+LL | |         _ => (),
+LL | |     };
+   | |_____^
    |
-   = note: `-D single-match` implied by `-D warnings`
+   = note: `-D clippy::single-match` implied by `-D warnings`
+help: try this
+   |
+LL |     if let Some(y) = x {
+LL |     println!("{:?}", y);
+LL | };
+   |
+
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:16:5
+   |
+LL | /     match x {
+LL | |         // Note the missing block braces.
+LL | |         // We suggest `if let Some(y) = x { .. }` because the macro
+LL | |         // is expanded before we can do anything.
+LL | |         Some(y) => println!("{:?}", y),
+LL | |         _ => (),
+LL | |     }
+   | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }`
 
 error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:15:5
+  --> $DIR/single_match.rs:25:5
    |
-15 | /     match z {
-16 | |         (2...3, 7...9) => dummy(),
-17 | |         _ => {}
-18 | |     };
+LL | /     match z {
+LL | |         (2...3, 7...9) => dummy(),
+LL | |         _ => {},
+LL | |     };
    | |_____^ help: try this: `if let (2...3, 7...9) = z { dummy() }`
 
 error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:41:5
+  --> $DIR/single_match.rs:54:5
    |
-41 | /     match x {
-42 | |         Some(y) => dummy(),
-43 | |         None => ()
-44 | |     };
+LL | /     match x {
+LL | |         Some(y) => dummy(),
+LL | |         None => (),
+LL | |     };
    | |_____^ help: try this: `if let Some(y) = x { dummy() }`
 
 error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:46:5
+  --> $DIR/single_match.rs:59:5
    |
-46 | /     match y {
-47 | |         Ok(y) => dummy(),
-48 | |         Err(..) => ()
-49 | |     };
+LL | /     match y {
+LL | |         Ok(y) => dummy(),
+LL | |         Err(..) => (),
+LL | |     };
    | |_____^ help: try this: `if let Ok(y) = y { dummy() }`
 
 error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:53:5
+  --> $DIR/single_match.rs:66:5
    |
-53 | /     match c {
-54 | |         Cow::Borrowed(..) => dummy(),
-55 | |         Cow::Owned(..) => (),
-56 | |     };
+LL | /     match c {
+LL | |         Cow::Borrowed(..) => dummy(),
+LL | |         Cow::Owned(..) => (),
+LL | |     };
    | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs
new file mode 100644 (file)
index 0000000..37a99de
--- /dev/null
@@ -0,0 +1,21 @@
+#![warn(clippy::single_match_else)]
+
+enum ExprNode {
+    ExprAddrOf,
+    Butterflies,
+    Unicorns,
+}
+
+static NODE: ExprNode = ExprNode::Unicorns;
+
+fn unwrap_addr() -> Option<&'static ExprNode> {
+    match ExprNode::Butterflies {
+        ExprNode::ExprAddrOf => Some(&NODE),
+        _ => {
+            let x = 5;
+            None
+        },
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr
new file mode 100644 (file)
index 0000000..3f29f5a
--- /dev/null
@@ -0,0 +1,23 @@
+error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match_else.rs:12:5
+   |
+LL | /     match ExprNode::Butterflies {
+LL | |         ExprNode::ExprAddrOf => Some(&NODE),
+LL | |         _ => {
+LL | |             let x = 5;
+LL | |             None
+LL | |         },
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::single-match-else` implied by `-D warnings`
+help: try this
+   |
+LL |     if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else {
+LL |     let x = 5;
+LL |     None
+LL | }
+   |
+
+error: aborting due to previous error
+
diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs
new file mode 100644 (file)
index 0000000..c5ae3ff
--- /dev/null
@@ -0,0 +1,63 @@
+use std::iter::repeat;
+
+fn main() {
+    resize_vector();
+    extend_vector();
+    mixed_extend_resize_vector();
+}
+
+fn extend_vector() {
+    // Extend with constant expression
+    let len = 300;
+    let mut vec1 = Vec::with_capacity(len);
+    vec1.extend(repeat(0).take(len));
+
+    // Extend with len expression
+    let mut vec2 = Vec::with_capacity(len - 10);
+    vec2.extend(repeat(0).take(len - 10));
+
+    // Extend with mismatching expression should not be warned
+    let mut vec3 = Vec::with_capacity(24322);
+    vec3.extend(repeat(0).take(2));
+}
+
+fn mixed_extend_resize_vector() {
+    // Mismatching len
+    let mut mismatching_len = Vec::with_capacity(30);
+    mismatching_len.extend(repeat(0).take(40));
+
+    // Slow initialization
+    let mut resized_vec = Vec::with_capacity(30);
+    resized_vec.resize(30, 0);
+
+    let mut extend_vec = Vec::with_capacity(30);
+    extend_vec.extend(repeat(0).take(30));
+}
+
+fn resize_vector() {
+    // Resize with constant expression
+    let len = 300;
+    let mut vec1 = Vec::with_capacity(len);
+    vec1.resize(len, 0);
+
+    // Resize mismatch len
+    let mut vec2 = Vec::with_capacity(200);
+    vec2.resize(10, 0);
+
+    // Resize with len expression
+    let mut vec3 = Vec::with_capacity(len - 10);
+    vec3.resize(len - 10, 0);
+
+    // Reinitialization should be warned
+    vec1 = Vec::with_capacity(10);
+    vec1.resize(10, 0);
+}
+
+fn do_stuff(vec: &mut Vec<u8>) {}
+
+fn extend_vector_with_manipulations_between() {
+    let len = 300;
+    let mut vec1: Vec<u8> = Vec::with_capacity(len);
+    do_stuff(&mut vec1);
+    vec1.extend(repeat(0).take(len));
+}
diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr
new file mode 100644 (file)
index 0000000..5d2788e
--- /dev/null
@@ -0,0 +1,60 @@
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:13:5
+   |
+LL |     let mut vec1 = Vec::with_capacity(len);
+   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+LL |     vec1.extend(repeat(0).take(len));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:17:5
+   |
+LL |     let mut vec2 = Vec::with_capacity(len - 10);
+   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+LL |     vec2.extend(repeat(0).take(len - 10));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:31:5
+   |
+LL |     let mut resized_vec = Vec::with_capacity(30);
+   |                           ---------------------- help: consider replace allocation with: `vec![0; 30]`
+LL |     resized_vec.resize(30, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:34:5
+   |
+LL |     let mut extend_vec = Vec::with_capacity(30);
+   |                          ---------------------- help: consider replace allocation with: `vec![0; 30]`
+LL |     extend_vec.extend(repeat(0).take(30));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:41:5
+   |
+LL |     let mut vec1 = Vec::with_capacity(len);
+   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+LL |     vec1.resize(len, 0);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:49:5
+   |
+LL |     let mut vec3 = Vec::with_capacity(len - 10);
+   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+LL |     vec3.resize(len - 10, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:53:5
+   |
+LL |     vec1 = Vec::with_capacity(10);
+   |            ---------------------- help: consider replace allocation with: `vec![0; 10]`
+LL |     vec1.resize(10, 0);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/slow_vector_initialization.stdout b/tests/ui/slow_vector_initialization.stdout
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed
new file mode 100644 (file)
index 0000000..7dfcf9c
--- /dev/null
@@ -0,0 +1,46 @@
+// run-rustfix
+#![allow(dead_code, unused_must_use)]
+
+fn main() {}
+
+#[allow(clippy::unnecessary_operation)]
+fn starts_with() {
+    "".starts_with(' ');
+    !"".starts_with(' ');
+}
+
+fn chars_cmp_with_unwrap() {
+    let s = String::from("foo");
+    if s.starts_with('f') {
+        // s.starts_with('f')
+        // Nothing here
+    }
+    if s.ends_with('o') {
+        // s.ends_with('o')
+        // Nothing here
+    }
+    if s.ends_with('o') {
+        // s.ends_with('o')
+        // Nothing here
+    }
+    if !s.starts_with('f') {
+        // !s.starts_with('f')
+        // Nothing here
+    }
+    if !s.ends_with('o') {
+        // !s.ends_with('o')
+        // Nothing here
+    }
+    if !s.ends_with('o') {
+        // !s.ends_with('o')
+        // Nothing here
+    }
+}
+
+#[allow(clippy::unnecessary_operation)]
+fn ends_with() {
+    "".ends_with(' ');
+    !"".ends_with(' ');
+    "".ends_with(' ');
+    !"".ends_with(' ');
+}
index d47c8a5b076833fa16606f1f3226b834d4dee325..e48a4246354391000da93003a6347b02bafbd0cc 100644 (file)
@@ -1,8 +1,9 @@
-#![allow(dead_code)]
+// run-rustfix
+#![allow(dead_code, unused_must_use)]
 
 fn main() {}
 
-#[allow(unnecessary_operation)]
+#[allow(clippy::unnecessary_operation)]
 fn starts_with() {
     "".chars().next() == Some(' ');
     Some(' ') != "".chars().next();
@@ -10,27 +11,33 @@ fn starts_with() {
 
 fn chars_cmp_with_unwrap() {
     let s = String::from("foo");
-    if s.chars().next().unwrap() == 'f' { // s.starts_with('f')
+    if s.chars().next().unwrap() == 'f' {
+        // s.starts_with('f')
         // Nothing here
     }
-    if s.chars().next_back().unwrap() == 'o' { // s.ends_with('o')
+    if s.chars().next_back().unwrap() == 'o' {
+        // s.ends_with('o')
         // Nothing here
     }
-    if s.chars().last().unwrap() == 'o' { // s.ends_with('o')
+    if s.chars().last().unwrap() == 'o' {
+        // s.ends_with('o')
         // Nothing here
     }
-    if s.chars().next().unwrap() != 'f' { // !s.starts_with('f')
+    if s.chars().next().unwrap() != 'f' {
+        // !s.starts_with('f')
         // Nothing here
     }
-    if s.chars().next_back().unwrap() != 'o' { // !s.ends_with('o')
+    if s.chars().next_back().unwrap() != 'o' {
+        // !s.ends_with('o')
         // Nothing here
     }
-    if s.chars().last().unwrap() != 'o' { // !s.ends_with('o')
+    if s.chars().last().unwrap() != 'o' {
+        // !s.ends_with('o')
         // Nothing here
     }
 }
 
-#[allow(unnecessary_operation)]
+#[allow(clippy::unnecessary_operation)]
 fn ends_with() {
     "".chars().last() == Some(' ');
     Some(' ') != "".chars().last();
index 7d73f201b692404d5250061459ff47cd97ff3947..7c726d0e010263ffca9352d1c41325cb042e9e86 100644 (file)
@@ -1,77 +1,77 @@
 error: you should use the `starts_with` method
--> $DIR/starts_ends_with.rs:7:5
-  |
-7 |     "".chars().next() == Some(' ');
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')`
-  |
-  = note: `-D chars-next-cmp` implied by `-D warnings`
 --> $DIR/starts_ends_with.rs:8:5
+   |
+LL |     "".chars().next() == Some(' ');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with(' ')`
+   |
+   = note: `-D clippy::chars-next-cmp` implied by `-D warnings`
 
 error: you should use the `starts_with` method
--> $DIR/starts_ends_with.rs:8:5
-  |
-8 |     Some(' ') != "".chars().next();
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')`
 --> $DIR/starts_ends_with.rs:9:5
+   |
+LL |     Some(' ') != "".chars().next();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')`
 
 error: you should use the `starts_with` method
-  --> $DIR/starts_ends_with.rs:13:8
+  --> $DIR/starts_ends_with.rs:14:8
    |
-13 |     if s.chars().next().unwrap() == 'f' { // s.starts_with('f')
+LL |     if s.chars().next().unwrap() == 'f' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:16:8
+  --> $DIR/starts_ends_with.rs:18:8
    |
-16 |     if s.chars().next_back().unwrap() == 'o' { // s.ends_with('o')
+LL |     if s.chars().next_back().unwrap() == 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')`
    |
-   = note: `-D chars-last-cmp` implied by `-D warnings`
+   = note: `-D clippy::chars-last-cmp` implied by `-D warnings`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:19:8
+  --> $DIR/starts_ends_with.rs:22:8
    |
-19 |     if s.chars().last().unwrap() == 'o' { // s.ends_with('o')
+LL |     if s.chars().last().unwrap() == 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')`
 
 error: you should use the `starts_with` method
-  --> $DIR/starts_ends_with.rs:22:8
+  --> $DIR/starts_ends_with.rs:26:8
    |
-22 |     if s.chars().next().unwrap() != 'f' { // !s.starts_with('f')
+LL |     if s.chars().next().unwrap() != 'f' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:25:8
+  --> $DIR/starts_ends_with.rs:30:8
    |
-25 |     if s.chars().next_back().unwrap() != 'o' { // !s.ends_with('o')
+LL |     if s.chars().next_back().unwrap() != 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:28:8
+  --> $DIR/starts_ends_with.rs:34:8
    |
-28 |     if s.chars().last().unwrap() != 'o' { // !s.ends_with('o')
+LL |     if s.chars().last().unwrap() != 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:35:5
+  --> $DIR/starts_ends_with.rs:42:5
    |
-35 |     "".chars().last() == Some(' ');
+LL |     "".chars().last() == Some(' ');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:36:5
+  --> $DIR/starts_ends_with.rs:43:5
    |
-36 |     Some(' ') != "".chars().last();
+LL |     Some(' ') != "".chars().last();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:37:5
+  --> $DIR/starts_ends_with.rs:44:5
    |
-37 |     "".chars().next_back() == Some(' ');
+LL |     "".chars().next_back() == Some(' ');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:38:5
+  --> $DIR/starts_ends_with.rs:45:5
    |
-38 |     Some(' ') != "".chars().next_back();
+LL |     Some(' ') != "".chars().next_back();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')`
 
 error: aborting due to 12 previous errors
diff --git a/tests/ui/string_extend.fixed b/tests/ui/string_extend.fixed
new file mode 100644 (file)
index 0000000..1883a9f
--- /dev/null
@@ -0,0 +1,32 @@
+// run-rustfix
+
+#[derive(Copy, Clone)]
+struct HasChars;
+
+impl HasChars {
+    fn chars(self) -> std::str::Chars<'static> {
+        "HasChars".chars()
+    }
+}
+
+fn main() {
+    let abc = "abc";
+    let def = String::from("def");
+    let mut s = String::new();
+
+    s.push_str(abc);
+    s.push_str(abc);
+
+    s.push_str("abc");
+    s.push_str("abc");
+
+    s.push_str(&def);
+    s.push_str(&def);
+
+    s.extend(abc.chars().skip(1));
+    s.extend("abc".chars().skip(1));
+    s.extend(['a', 'b', 'c'].iter());
+
+    let f = HasChars;
+    s.extend(f.chars());
+}
index d99adb19f892fdec95fad3addaf894268842d5e4..07d0baa1be6c7ee5ecbf653ec408b491d959de48 100644 (file)
@@ -1,3 +1,5 @@
+// run-rustfix
+
 #[derive(Copy, Clone)]
 struct HasChars;
 
index 4be2037ad31bbb915076214e79373575efff1975..6af8c9e1662b5b970237dfe206e83ce6b13cc8be 100644 (file)
@@ -1,21 +1,21 @@
 error: calling `.extend(_.chars())`
-  --> $DIR/string_extend.rs:16:5
+  --> $DIR/string_extend.rs:18:5
    |
-16 |     s.extend(abc.chars());
+LL |     s.extend(abc.chars());
    |     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)`
    |
-   = note: `-D string-extend-chars` implied by `-D warnings`
+   = note: `-D clippy::string-extend-chars` implied by `-D warnings`
 
 error: calling `.extend(_.chars())`
-  --> $DIR/string_extend.rs:19:5
+  --> $DIR/string_extend.rs:21:5
    |
-19 |     s.extend("abc".chars());
+LL |     s.extend("abc".chars());
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")`
 
 error: calling `.extend(_.chars())`
-  --> $DIR/string_extend.rs:22:5
+  --> $DIR/string_extend.rs:24:5
    |
-22 |     s.extend(def.chars());
+LL |     s.extend(def.chars());
    |     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed
new file mode 100644 (file)
index 0000000..a705046
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+#![warn(clippy::string_lit_as_bytes)]
+
+fn str_lit_as_bytes() {
+    let bs = b"hello there";
+
+    let bs = br###"raw string with three ### in it and some " ""###;
+
+    // no warning, because this cannot be written as a byte string literal:
+    let ubs = "☃".as_bytes();
+
+    let strify = stringify!(foobar).as_bytes();
+
+    let includestr = include_bytes!("entry.rs");
+}
+
+fn main() {}
diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs
new file mode 100644 (file)
index 0000000..ea8c712
--- /dev/null
@@ -0,0 +1,19 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+#![warn(clippy::string_lit_as_bytes)]
+
+fn str_lit_as_bytes() {
+    let bs = "hello there".as_bytes();
+
+    let bs = r###"raw string with three ### in it and some " ""###.as_bytes();
+
+    // no warning, because this cannot be written as a byte string literal:
+    let ubs = "☃".as_bytes();
+
+    let strify = stringify!(foobar).as_bytes();
+
+    let includestr = include_str!("entry.rs").as_bytes();
+}
+
+fn main() {}
diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr
new file mode 100644 (file)
index 0000000..f51cd71
--- /dev/null
@@ -0,0 +1,22 @@
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:7:14
+   |
+LL |     let bs = "hello there".as_bytes();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
+   |
+   = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
+
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:9:14
+   |
+LL |     let bs = r###"raw string with three ### in it and some " ""###.as_bytes();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with three ### in it and some " ""###`
+
+error: calling `as_bytes()` on `include_str!(..)`
+  --> $DIR/string_lit_as_bytes.rs:16:22
+   |
+LL |     let includestr = include_str!("entry.rs").as_bytes();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry.rs")`
+
+error: aborting due to 3 previous errors
+
index 66d24a3c0702ae0e130037a065f735acbe935d64..766e23c744a577a4cb0ff88d64b9ef4e287bab0b 100644 (file)
@@ -1,9 +1,7 @@
-
-
-
-#[warn(string_add)]
-#[allow(string_add_assign)]
-fn add_only() { // ignores assignment distinction
+#[warn(clippy::string_add)]
+#[allow(clippy::string_add_assign)]
+fn add_only() {
+    // ignores assignment distinction
     let mut x = "".to_owned();
 
     for _ in 1..3 {
@@ -16,7 +14,7 @@ fn add_only() { // ignores assignment distinction
     assert_eq!(&x, &z);
 }
 
-#[warn(string_add_assign)]
+#[warn(clippy::string_add_assign)]
 fn add_assign_only() {
     let mut x = "".to_owned();
 
@@ -30,7 +28,7 @@ fn add_assign_only() {
     assert_eq!(&x, &z);
 }
 
-#[warn(string_add, string_add_assign)]
+#[warn(clippy::string_add, clippy::string_add_assign)]
 fn both() {
     let mut x = "".to_owned();
 
@@ -44,17 +42,7 @@ fn both() {
     assert_eq!(&x, &z);
 }
 
-#[allow(dead_code, unused_variables)]
-#[warn(string_lit_as_bytes)]
-fn str_lit_as_bytes() {
-    let bs = "hello there".as_bytes();
-
-    // no warning, because this cannot be written as a byte string literal:
-    let ubs = "☃".as_bytes();
-
-    let strify = stringify!(foobar).as_bytes();
-}
-
+#[allow(clippy::assign_op_pattern)]
 fn main() {
     add_only();
     add_assign_only();
@@ -62,6 +50,6 @@ fn main() {
 
     // the add is only caught for `String`
     let mut x = 1;
-    x = x + 1;
+    x = x + 1;
     assert_eq!(2, x);
 }
index d098ce9df5eaf0969ca7565aa0e05bd0489834e9..7f684fe63555e00fef23c57ce34de684fbf089df 100644 (file)
@@ -1,76 +1,56 @@
 error: manual implementation of an assign operation
-  --> $DIR/strings.rs:10:9
+  --> $DIR/strings.rs:8:9
    |
-10 |         x = x + ".";
+LL |         x = x + ".";
    |         ^^^^^^^^^^^ help: replace it with: `x += "."`
    |
-   = note: `-D assign-op-pattern` implied by `-D warnings`
+   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
 
 error: you added something to a string. Consider using `String::push_str()` instead
-  --> $DIR/strings.rs:10:13
+  --> $DIR/strings.rs:8:13
    |
-10 |         x = x + ".";
+LL |         x = x + ".";
    |             ^^^^^^^
    |
-   = note: `-D string-add` implied by `-D warnings`
+   = note: `-D clippy::string-add` implied by `-D warnings`
 
 error: you added something to a string. Consider using `String::push_str()` instead
-  --> $DIR/strings.rs:14:13
+  --> $DIR/strings.rs:12:13
    |
-14 |     let z = y + "...";
+LL |     let z = y + "...";
    |             ^^^^^^^^^
 
 error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead
-  --> $DIR/strings.rs:24:9
+  --> $DIR/strings.rs:22:9
    |
-24 |         x = x + ".";
+LL |         x = x + ".";
    |         ^^^^^^^^^^^
    |
-   = note: `-D string-add-assign` implied by `-D warnings`
+   = note: `-D clippy::string-add-assign` implied by `-D warnings`
 
 error: manual implementation of an assign operation
-  --> $DIR/strings.rs:24:9
+  --> $DIR/strings.rs:22:9
    |
-24 |         x = x + ".";
+LL |         x = x + ".";
    |         ^^^^^^^^^^^ help: replace it with: `x += "."`
 
 error: you assigned the result of adding something to this string. Consider using `String::push_str()` instead
-  --> $DIR/strings.rs:38:9
+  --> $DIR/strings.rs:36:9
    |
-38 |         x = x + ".";
+LL |         x = x + ".";
    |         ^^^^^^^^^^^
 
 error: manual implementation of an assign operation
-  --> $DIR/strings.rs:38:9
+  --> $DIR/strings.rs:36:9
    |
-38 |         x = x + ".";
+LL |         x = x + ".";
    |         ^^^^^^^^^^^ help: replace it with: `x += "."`
 
 error: you added something to a string. Consider using `String::push_str()` instead
-  --> $DIR/strings.rs:42:13
+  --> $DIR/strings.rs:40:13
    |
-42 |     let z = y + "...";
+LL |     let z = y + "...";
    |             ^^^^^^^^^
 
-error: calling `as_bytes()` on a string literal
-  --> $DIR/strings.rs:50:14
-   |
-50 |     let bs = "hello there".as_bytes();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
-   |
-   = note: `-D string-lit-as-bytes` implied by `-D warnings`
-
-error: calling `as_bytes()` on a string literal
-  --> $DIR/strings.rs:55:18
-   |
-55 |     let strify = stringify!(foobar).as_bytes();
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `bstringify!(foobar)`
-
-error: manual implementation of an assign operation
-  --> $DIR/strings.rs:65:7
-   |
-65 |     ; x = x + 1;
-   |       ^^^^^^^^^ help: replace it with: `x += 1`
-
-error: aborting due to 11 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/stutter.rs b/tests/ui/stutter.rs
deleted file mode 100644 (file)
index 761339b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-#![warn(stutter)]
-#![allow(dead_code)]
-
-mod foo {
-    pub fn foo() {}
-    pub fn foo_bar() {}
-    pub fn bar_foo() {}
-    pub struct FooCake {}
-    pub enum CakeFoo {}
-    pub struct Foo7Bar;
-
-    // Should not warn
-    pub struct Foobar;
-}
-
-fn main() {}
diff --git a/tests/ui/stutter.stderr b/tests/ui/stutter.stderr
deleted file mode 100644 (file)
index 25e8579..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-error: item name starts with its containing module's name
- --> $DIR/stutter.rs:8:5
-  |
-8 |     pub fn foo_bar() {}
-  |     ^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D stutter` implied by `-D warnings`
-
-error: item name ends with its containing module's name
- --> $DIR/stutter.rs:9:5
-  |
-9 |     pub fn bar_foo() {}
-  |     ^^^^^^^^^^^^^^^^^^^
-
-error: item name starts with its containing module's name
-  --> $DIR/stutter.rs:10:5
-   |
-10 |     pub struct FooCake {}
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
-error: item name ends with its containing module's name
-  --> $DIR/stutter.rs:11:5
-   |
-11 |     pub enum CakeFoo {}
-   |     ^^^^^^^^^^^^^^^^^^^
-
-error: item name starts with its containing module's name
-  --> $DIR/stutter.rs:12:5
-   |
-12 |     pub struct Foo7Bar;
-   |     ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
-
index 9f6fce2495a3dfdbfd82e10957744fc8e93341d6..6ee924d3b2eda6f88f295686c8d9d20ea5a82d90 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(suspicious_arithmetic_impl)]
-use std::ops::{Add, AddAssign, Mul, Sub, Div};
+#![warn(clippy::suspicious_arithmetic_impl)]
+use std::ops::{Add, AddAssign, Div, Mul, Sub};
 
 #[derive(Copy, Clone)]
 struct Foo(u32);
index 8130b1cb31abeb86377001387a4d6e636b44a49b..f818f7b3d95644dc557a83172b671769e52f3b04 100644 (file)
@@ -1,18 +1,18 @@
 error: Suspicious use of binary operator in `Add` impl
-  --> $DIR/suspicious_arithmetic_impl.rs:14:20
+  --> $DIR/suspicious_arithmetic_impl.rs:11:20
    |
-14 |         Foo(self.0 - other.0)
+LL |         Foo(self.0 - other.0)
    |                    ^
    |
-   = note: `-D suspicious-arithmetic-impl` implied by `-D warnings`
+   = note: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings`
 
 error: Suspicious use of binary operator in `AddAssign` impl
-  --> $DIR/suspicious_arithmetic_impl.rs:20:23
+  --> $DIR/suspicious_arithmetic_impl.rs:17:23
    |
-20 |         *self = *self - other;
+LL |         *self = *self - other;
    |                       ^
    |
-   = note: #[deny(suspicious_op_assign_impl)] on by default
+   = note: #[deny(clippy::suspicious_op_assign_impl)] on by default
 
 error: aborting due to 2 previous errors
 
index d1d12641c46afa4b9b8938d21022dac2ee2ea9de..77cfc16ff6ead0fd9d27746cff29bb9a0d6ad9bb 100644 (file)
@@ -1,8 +1,5 @@
-
-
-
-#![warn(clippy)]
-#![allow(blacklisted_name, unused_assignments)]
+#![warn(clippy::all)]
+#![allow(clippy::blacklisted_name, unused_assignments)]
 
 struct Foo(u32);
 
@@ -33,6 +30,7 @@ fn vec() {
     foo.swap(0, 1);
 }
 
+#[rustfmt::skip]
 fn main() {
     array();
     slice();
index a01ec375e639e7ccda1823d891f7ab8f2192bad0..5d818cf20566b6d1f4076bbc47faa53d835f98e5 100644 (file)
@@ -1,66 +1,66 @@
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:11:5
+  --> $DIR/swap.rs:8:5
    |
-11 | /     let temp = foo[0];
-12 | |     foo[0] = foo[1];
-13 | |     foo[1] = temp;
+LL | /     let temp = foo[0];
+LL | |     foo[0] = foo[1];
+LL | |     foo[1] = temp;
    | |_________________^ help: try: `foo.swap(0, 1)`
    |
-   = note: `-D manual-swap` implied by `-D warnings`
+   = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:20:5
+  --> $DIR/swap.rs:17:5
    |
-20 | /     let temp = foo[0];
-21 | |     foo[0] = foo[1];
-22 | |     foo[1] = temp;
+LL | /     let temp = foo[0];
+LL | |     foo[0] = foo[1];
+LL | |     foo[1] = temp;
    | |_________________^ help: try: `foo.swap(0, 1)`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:29:5
+  --> $DIR/swap.rs:26:5
    |
-29 | /     let temp = foo[0];
-30 | |     foo[0] = foo[1];
-31 | |     foo[1] = temp;
+LL | /     let temp = foo[0];
+LL | |     foo[0] = foo[1];
+LL | |     foo[1] = temp;
    | |_________________^ help: try: `foo.swap(0, 1)`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:47:7
+  --> $DIR/swap.rs:45:7
    |
-47 |       ; let t = a;
+LL |       ; let t = a;
    |  _______^
-48 | |     a = b;
-49 | |     b = t;
+LL | |     a = b;
+LL | |     b = t;
    | |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
    |
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:56:7
+  --> $DIR/swap.rs:54:7
    |
-56 |       ; let t = c.0;
+LL |       ; let t = c.0;
    |  _______^
-57 | |     c.0 = a;
-58 | |     a = t;
+LL | |     c.0 = a;
+LL | |     a = t;
    | |_________^ help: try: `std::mem::swap(&mut c.0, &mut a)`
    |
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:44:5
+  --> $DIR/swap.rs:42:5
    |
-44 | /     a = b;
-45 | |     b = a;
+LL | /     a = b;
+LL | |     b = a;
    | |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
    |
-   = note: `-D almost-swapped` implied by `-D warnings`
+   = note: `-D clippy::almost-swapped` implied by `-D warnings`
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:53:5
+  --> $DIR/swap.rs:51:5
    |
-53 | /     c.0 = a;
-54 | |     a = c.0;
+LL | /     c.0 = a;
+LL | |     a = c.0;
    | |___________^ help: try: `std::mem::swap(&mut c.0, &mut a)`
    |
    = note: or maybe you should use `std::mem::replace`?
index 8f25aad72bb5c7e35d8c1e37e1aa5060746c9bf8..c6c315d5fab5d359aa7378719722fdb9a8ead38c 100644 (file)
@@ -1,36 +1,75 @@
-
-
-
-#![warn(temporary_assignment)]
+#![warn(clippy::temporary_assignment)]
 
 use std::ops::{Deref, DerefMut};
 
+struct TupleStruct(i32);
+
 struct Struct {
-    field: i32
+    field: i32,
+}
+
+struct MultiStruct {
+    structure: Struct,
 }
 
 struct Wrapper<'a> {
-    inner: &'a mut Struct
+    inner: &'a mut Struct,
 }
 
 impl<'a> Deref for Wrapper<'a> {
     type Target = Struct;
-    fn deref(&self) -> &Struct { self.inner }
+    fn deref(&self) -> &Struct {
+        self.inner
+    }
 }
 
 impl<'a> DerefMut for Wrapper<'a> {
-    fn deref_mut(&mut self) -> &mut Struct { self.inner }
+    fn deref_mut(&mut self) -> &mut Struct {
+        self.inner
+    }
+}
+
+struct ArrayStruct {
+    array: [i32; 1],
 }
 
+const A: TupleStruct = TupleStruct(1);
+const B: Struct = Struct { field: 1 };
+const C: MultiStruct = MultiStruct {
+    structure: Struct { field: 1 },
+};
+const D: ArrayStruct = ArrayStruct { array: [1] };
+
 fn main() {
     let mut s = Struct { field: 0 };
     let mut t = (0, 0);
 
     Struct { field: 0 }.field = 1;
+    MultiStruct {
+        structure: Struct { field: 0 },
+    }
+    .structure
+    .field = 1;
+    ArrayStruct { array: [0] }.array[0] = 1;
     (0, 0).0 = 1;
 
+    A.0 = 2;
+    B.field = 2;
+    C.structure.field = 2;
+    D.array[0] = 2;
+
     // no error
     s.field = 1;
     t.0 = 1;
     Wrapper { inner: &mut s }.field = 1;
+    let mut a_mut = TupleStruct(1);
+    a_mut.0 = 2;
+    let mut b_mut = Struct { field: 1 };
+    b_mut.field = 2;
+    let mut c_mut = MultiStruct {
+        structure: Struct { field: 1 },
+    };
+    c_mut.structure.field = 2;
+    let mut d_mut = ArrayStruct { array: [1] };
+    d_mut.array[0] = 2;
 }
index 979720c914d16e49299a341b44cd1d28c1ff2862..4efe2d4bb6713625bd6b02fb299670e32e135155 100644 (file)
@@ -1,16 +1,56 @@
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:29:5
+  --> $DIR/temporary_assignment.rs:47:5
    |
-29 |     Struct { field: 0 }.field = 1;
+LL |     Struct { field: 0 }.field = 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D temporary-assignment` implied by `-D warnings`
+   = note: `-D clippy::temporary-assignment` implied by `-D warnings`
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:30:5
+  --> $DIR/temporary_assignment.rs:48:5
    |
-30 |     (0, 0).0 = 1;
+LL | /     MultiStruct {
+LL | |         structure: Struct { field: 0 },
+LL | |     }
+LL | |     .structure
+LL | |     .field = 1;
+   | |______________^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:53:5
+   |
+LL |     ArrayStruct { array: [0] }.array[0] = 1;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:54:5
+   |
+LL |     (0, 0).0 = 1;
    |     ^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:56:5
+   |
+LL |     A.0 = 2;
+   |     ^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:57:5
+   |
+LL |     B.field = 2;
+   |     ^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:58:5
+   |
+LL |     C.structure.field = 2;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: assignment to temporary
+  --> $DIR/temporary_assignment.rs:59:5
+   |
+LL |     D.array[0] = 2;
+   |     ^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
 
index a0d6dd2dabd593b464c2b7c24f3c66ac43f12631..a412c387a0dd0814f32a7af1986cf49baa7185c0 100644 (file)
@@ -1,28 +1,29 @@
-
-
-
-#![warn(clippy)]
+#![warn(clippy::all)]
 #![allow(unused)]
 
 fn the_answer(ref mut x: u8) {
-  *x = 42;
+    *x = 42;
 }
 
 fn main() {
-  let mut x = 0;
-  the_answer(x);
-  // Closures should not warn
-  let y = |ref x| { println!("{:?}", x) };
-  y(1u8);
+    let mut x = 0;
+    the_answer(x);
+    // Closures should not warn
+    let y = |ref x| println!("{:?}", x);
+    y(1u8);
+
+    let ref x = 1;
 
-  let ref x = 1;
+    let ref y: (&_, u8) = (&1, 2);
 
-  let ref y: (&_, u8) = (&1, 2);
+    let ref z = 1 + 2;
 
-  let ref z = 1 + 2;
+    let ref mut z = 1 + 2;
 
-  let ref mut z = 1 + 2;
+    let (ref x, _) = (1, 2); // ok, not top level
+    println!("The answer is {}.", x);
 
-  let (ref x, _) = (1,2); // okay, not top level
-  println!("The answer is {}.", x);
+    // Make sure that allowing the lint works
+    #[allow(clippy::toplevel_ref_arg)]
+    let ref mut x = 1_234_543;
 }
index f360e85329f50729f17bc498ba0bee3e8b7336cc..00a753c6ac29ba5f798d8dcf74dd1c003426d123 100644 (file)
@@ -1,34 +1,34 @@
 error: `ref` directly on a function argument is ignored. Consider using a reference type instead.
--> $DIR/toplevel_ref_arg.rs:7:15
-  |
-7 | fn the_answer(ref mut x: u8) {
-  |               ^^^^^^^^^
-  |
-  = note: `-D toplevel-ref-arg` implied by `-D warnings`
 --> $DIR/toplevel_ref_arg.rs:4:15
+   |
+LL | fn the_answer(ref mut x: u8) {
+   |               ^^^^^^^^^
+   |
+   = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:18:7
+  --> $DIR/toplevel_ref_arg.rs:15:9
    |
-18 |   let ref x = 1;
-   |   ----^^^^^----- help: try: `let x = &1;`
+LL |     let ref x = 1;
+   |     ----^^^^^----- help: try: `let x = &1;`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:20:7
+  --> $DIR/toplevel_ref_arg.rs:17:9
    |
-20 |   let ref y: (&_, u8) = (&1, 2);
-   |   ----^^^^^--------------------- help: try: `let y: &(&_, u8) = &(&1, 2);`
+LL |     let ref y: (&_, u8) = (&1, 2);
+   |     ----^^^^^--------------------- help: try: `let y: &(&_, u8) = &(&1, 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:22:7
+  --> $DIR/toplevel_ref_arg.rs:19:9
    |
-22 |   let ref z = 1 + 2;
-   |   ----^^^^^--------- help: try: `let z = &(1 + 2);`
+LL |     let ref z = 1 + 2;
+   |     ----^^^^^--------- help: try: `let z = &(1 + 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:24:7
+  --> $DIR/toplevel_ref_arg.rs:21:9
    |
-24 |   let ref mut z = 1 + 2;
-   |   ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);`
+LL |     let ref mut z = 1 + 2;
+   |     ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);`
 
 error: aborting due to 5 previous errors
 
index 5494e78062813bbb92c99e23157c2f33147d5abf..4ee5ecffb8763210ad43a85047a33adf9c8358a6 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(stmt_expr_attributes, tool_attributes)]
-
+#![feature(stmt_expr_attributes)]
 #![allow(unused_parens)]
 
 fn main() {
     let x: i32 = 42;
-    let _ = #[clippy::author] (x & 0b1111 == 0);  // suggest trailing_zeros
+    let _ = #[clippy::author]
+    (x & 0b1111 == 0); // suggest trailing_zeros
     let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
     let _ = x & 0b1_1010 == 0; // do not lint
     let _ = x & 1 == 0; // do not lint
index 47b46be9ba805b4879c7c772cfe74a7b7e64fe5e..61289b2447141370fd09f56bcdb133f0a60e0cf8 100644 (file)
@@ -1,16 +1,16 @@
 error: bit mask could be simplified with a call to `trailing_zeros`
- --> $DIR/trailing_zeros.rs:7:31
-  |
-7 |     let _ = #[clippy::author] (x & 0b1111 == 0);  // suggest trailing_zeros
-  |                               ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4`
-  |
-  = note: `-D verbose-bit-mask` implied by `-D warnings`
+  --> $DIR/trailing_zeros.rs:7:5
+   |
+LL |     (x & 0b1111 == 0); // suggest trailing_zeros
+   |     ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 4`
+   |
+   = note: `-D clippy::verbose-bit-mask` implied by `-D warnings`
 
 error: bit mask could be simplified with a call to `trailing_zeros`
- --> $DIR/trailing_zeros.rs:8:13
-  |
-8 |     let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
-  |             ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5`
 --> $DIR/trailing_zeros.rs:8:13
+   |
+LL |     let _ = x & 0b1_1111 == 0; // suggest trailing_zeros
+   |             ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5`
 
 error: aborting due to 2 previous errors
 
index 54e1734e1415b46bc4aef6f4f002db83bff681f0..86964f8480a48802ed6eacd69f74015e172c3044 100644 (file)
@@ -1,6 +1,3 @@
-
-
-
 #![allow(dead_code)]
 
 extern crate core;
@@ -16,8 +13,8 @@ fn my_vec() -> MyVec<i32> {
     vec![]
 }
 
-#[allow(needless_lifetimes, transmute_ptr_to_ptr)]
-#[warn(useless_transmute)]
+#[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)]
+#[warn(clippy::useless_transmute)]
 unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
     let _: &'a T = core::intrinsics::transmute(t);
 
@@ -30,7 +27,7 @@ unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
     let _: *const U = core::intrinsics::transmute(t);
 }
 
-#[warn(transmute_ptr_to_ref)]
+#[warn(clippy::transmute_ptr_to_ref)]
 unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     let _: &T = std::mem::transmute(p);
     let _: &T = &*p;
@@ -54,7 +51,7 @@ unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
     let _: &T = &*(om as *const T);
 }
 
-#[warn(transmute_ptr_to_ref)]
+#[warn(clippy::transmute_ptr_to_ref)]
 fn issue1231() {
     struct Foo<'a, T: 'a> {
         bar: &'a T,
@@ -70,7 +67,7 @@ struct Foo<'a, T: 'a> {
     unsafe { std::mem::transmute::<_, Bar>(raw) };
 }
 
-#[warn(useless_transmute)]
+#[warn(clippy::useless_transmute)]
 fn useless() {
     unsafe {
         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
@@ -91,17 +88,17 @@ fn useless() {
 
         let _: *const usize = std::mem::transmute(5_isize);
 
-        let _  = 5_isize as *const usize;
+        let _ = 5_isize as *const usize;
 
-        let _: *const usize = std::mem::transmute(1+1usize);
+        let _: *const usize = std::mem::transmute(1 + 1usize);
 
-        let _  = (1+1_usize) as *const usize;
+        let _ = (1 + 1_usize) as *const usize;
     }
 }
 
 struct Usize(usize);
 
-#[warn(crosspointer_transmute)]
+#[warn(clippy::crosspointer_transmute)]
 fn crosspointer() {
     let mut int: Usize = Usize(0);
     let int_const_ptr: *const Usize = &int as *const Usize;
@@ -118,18 +115,18 @@ fn crosspointer() {
     }
 }
 
-#[warn(transmute_int_to_char)]
+#[warn(clippy::transmute_int_to_char)]
 fn int_to_char() {
     let _: char = unsafe { std::mem::transmute(0_u32) };
     let _: char = unsafe { std::mem::transmute(0_i32) };
 }
 
-#[warn(transmute_int_to_bool)]
+#[warn(clippy::transmute_int_to_bool)]
 fn int_to_bool() {
     let _: bool = unsafe { std::mem::transmute(0_u8) };
 }
 
-#[warn(transmute_int_to_float)]
+#[warn(clippy::transmute_int_to_float)]
 fn int_to_float() {
     let _: f32 = unsafe { std::mem::transmute(0_u32) };
     let _: f32 = unsafe { std::mem::transmute(0_i32) };
@@ -144,13 +141,13 @@ fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
 // of transmute
 
 // Make sure we can do static lifetime transmutes
-#[warn(transmute_ptr_to_ptr)]
+#[warn(clippy::transmute_ptr_to_ptr)]
 unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
     std::mem::transmute::<&'a T, &'static T>(t)
 }
 
 // Make sure we can do non-static lifetime transmutes
-#[warn(transmute_ptr_to_ptr)]
+#[warn(clippy::transmute_ptr_to_ptr)]
 unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
     std::mem::transmute::<&'a T, &'b T>(t)
 }
@@ -163,7 +160,7 @@ struct GenericParam<T> {
     t: T,
 }
 
-#[warn(transmute_ptr_to_ptr)]
+#[warn(clippy::transmute_ptr_to_ptr)]
 fn transmute_ptr_to_ptr() {
     let ptr = &1u32 as *const u32;
     let mut_ptr = &mut 1u32 as *mut u32;
@@ -191,9 +188,7 @@ fn transmute_ptr_to_ptr() {
     let s = "hello world".to_owned();
     let lp = LifetimeParam { s: &s };
     let _: &LifetimeParam<'static> = unsafe { std::mem::transmute(&lp) };
-    let _: &GenericParam<&LifetimeParam<'static>> = unsafe {
-        std::mem::transmute(&GenericParam { t: &lp})
-    };
+    let _: &GenericParam<&LifetimeParam<'static>> = unsafe { std::mem::transmute(&GenericParam { t: &lp }) };
 }
 
-fn main() { }
+fn main() {}
index abed5065c0a14dd1e992594d0121e15c04b7a3ef..ceee86d224db9d9e8527cc59e5d47a48afb49fa5 100644 (file)
 error: transmute from a type (`&'a T`) to itself
-  --> $DIR/transmute.rs:22:20
+  --> $DIR/transmute.rs:19:20
    |
-22 |     let _: &'a T = core::intrinsics::transmute(t);
+LL |     let _: &'a T = core::intrinsics::transmute(t);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D useless-transmute` implied by `-D warnings`
+   = note: `-D clippy::useless-transmute` implied by `-D warnings`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:26:23
+  --> $DIR/transmute.rs:23:23
    |
-26 |     let _: *const T = core::intrinsics::transmute(t);
+LL |     let _: *const T = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:28:21
+  --> $DIR/transmute.rs:25:21
    |
-28 |     let _: *mut T = core::intrinsics::transmute(t);
+LL |     let _: *mut T = core::intrinsics::transmute(t);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:30:23
+  --> $DIR/transmute.rs:27:23
    |
-30 |     let _: *const U = core::intrinsics::transmute(t);
+LL |     let _: *const U = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
-  --> $DIR/transmute.rs:35:17
+  --> $DIR/transmute.rs:32:17
    |
-35 |     let _: &T = std::mem::transmute(p);
+LL |     let _: &T = std::mem::transmute(p);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
    |
-   = note: `-D transmute-ptr-to-ref` implied by `-D warnings`
+   = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> $DIR/transmute.rs:38:21
+  --> $DIR/transmute.rs:35:21
    |
-38 |     let _: &mut T = std::mem::transmute(m);
+LL |     let _: &mut T = std::mem::transmute(m);
    |                     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
-  --> $DIR/transmute.rs:41:17
+  --> $DIR/transmute.rs:38:17
    |
-41 |     let _: &T = std::mem::transmute(m);
+LL |     let _: &T = std::mem::transmute(m);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
 
 error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
-  --> $DIR/transmute.rs:44:21
+  --> $DIR/transmute.rs:41:21
    |
-44 |     let _: &mut T = std::mem::transmute(p as *mut T);
+LL |     let _: &mut T = std::mem::transmute(p as *mut T);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
 
 error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
-  --> $DIR/transmute.rs:47:17
+  --> $DIR/transmute.rs:44:17
    |
-47 |     let _: &T = std::mem::transmute(o);
+LL |     let _: &T = std::mem::transmute(o);
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
-  --> $DIR/transmute.rs:50:21
+  --> $DIR/transmute.rs:47:21
    |
-50 |     let _: &mut T = std::mem::transmute(om);
+LL |     let _: &mut T = std::mem::transmute(om);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
 
 error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
-  --> $DIR/transmute.rs:53:17
+  --> $DIR/transmute.rs:50:17
    |
-53 |     let _: &T = std::mem::transmute(om);
+LL |     let _: &T = std::mem::transmute(om);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, u8>`)
-  --> $DIR/transmute.rs:64:32
+  --> $DIR/transmute.rs:61:32
    |
-64 |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
+LL |     let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<_>)`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&issue1231::Foo<'_, &u8>`)
-  --> $DIR/transmute.rs:66:33
+  --> $DIR/transmute.rs:63:33
    |
-66 |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
+LL |     let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const Foo<&_>)`
 
 error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
-  --> $DIR/transmute.rs:70:14
+  --> $DIR/transmute.rs:67:14
    |
-70 |     unsafe { std::mem::transmute::<_, Bar>(raw) };
+LL |     unsafe { std::mem::transmute::<_, Bar>(raw) };
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:76:27
+  --> $DIR/transmute.rs:73:27
    |
-76 |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
+LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:78:27
+  --> $DIR/transmute.rs:75:27
    |
-78 |         let _: Vec<i32> = core::mem::transmute(my_vec());
+LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:80:27
+  --> $DIR/transmute.rs:77:27
    |
-80 |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
+LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:82:27
+  --> $DIR/transmute.rs:79:27
    |
-82 |         let _: Vec<i32> = std::mem::transmute(my_vec());
+LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:84:27
+  --> $DIR/transmute.rs:81:27
    |
-84 |         let _: Vec<i32> = my_transmute(my_vec());
+LL |         let _: Vec<i32> = my_transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from an integer to a pointer
-  --> $DIR/transmute.rs:92:31
+  --> $DIR/transmute.rs:89:31
    |
-92 |         let _: *const usize = std::mem::transmute(5_isize);
+LL |         let _: *const usize = std::mem::transmute(5_isize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 
 error: transmute from an integer to a pointer
-  --> $DIR/transmute.rs:96:31
+  --> $DIR/transmute.rs:93:31
    |
-96 |         let _: *const usize = std::mem::transmute(1+1usize);
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1+1usize) as *const usize`
+LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-   --> $DIR/transmute.rs:111:24
-    |
-111 |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
-    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    |
-    = note: `-D crosspointer-transmute` implied by `-D warnings`
+  --> $DIR/transmute.rs:108:24
+   |
+LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
 
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-   --> $DIR/transmute.rs:113:24
-    |
-113 |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
-    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/transmute.rs:110:24
+   |
+LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-   --> $DIR/transmute.rs:115:31
-    |
-115 |         let _: *const Usize = core::intrinsics::transmute(my_int());
-    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/transmute.rs:112:31
+   |
+LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-   --> $DIR/transmute.rs:117:29
-    |
-117 |         let _: *mut Usize = core::intrinsics::transmute(my_int());
-    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  --> $DIR/transmute.rs:114:29
+   |
+LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u32` to a `char`
-   --> $DIR/transmute.rs:123:28
-    |
-123 |     let _: char = unsafe { std::mem::transmute(0_u32) };
-    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
-    |
-    = note: `-D transmute-int-to-char` implied by `-D warnings`
+  --> $DIR/transmute.rs:120:28
+   |
+LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
+   |
+   = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
 
 error: transmute from a `i32` to a `char`
-   --> $DIR/transmute.rs:124:28
-    |
-124 |     let _: char = unsafe { std::mem::transmute(0_i32) };
-    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
+  --> $DIR/transmute.rs:121:28
+   |
+LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
 
 error: transmute from a `u8` to a `bool`
-   --> $DIR/transmute.rs:129:28
-    |
-129 |     let _: bool = unsafe { std::mem::transmute(0_u8) };
-    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
-    |
-    = note: `-D transmute-int-to-bool` implied by `-D warnings`
+  --> $DIR/transmute.rs:126:28
+   |
+LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
+   |
+   = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
 
 error: transmute from a `u32` to a `f32`
-   --> $DIR/transmute.rs:134:27
-    |
-134 |     let _: f32 = unsafe { std::mem::transmute(0_u32) };
-    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
-    |
-    = note: `-D transmute-int-to-float` implied by `-D warnings`
+  --> $DIR/transmute.rs:131:27
+   |
+LL |     let _: f32 = unsafe { std::mem::transmute(0_u32) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
+   |
+   = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
 
 error: transmute from a `i32` to a `f32`
-   --> $DIR/transmute.rs:135:27
-    |
-135 |     let _: f32 = unsafe { std::mem::transmute(0_i32) };
-    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
+  --> $DIR/transmute.rs:132:27
+   |
+LL |     let _: f32 = unsafe { std::mem::transmute(0_i32) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
 
 error: transmute from a `&[u8]` to a `&str`
-   --> $DIR/transmute.rs:139:28
-    |
-139 |     let _: &str = unsafe { std::mem::transmute(b) };
-    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
-    |
-    = note: `-D transmute-bytes-to-str` implied by `-D warnings`
+  --> $DIR/transmute.rs:136:28
+   |
+LL |     let _: &str = unsafe { std::mem::transmute(b) };
+   |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
+   |
+   = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-   --> $DIR/transmute.rs:140:32
-    |
-140 |     let _: &mut str = unsafe { std::mem::transmute(mb) };
-    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
+  --> $DIR/transmute.rs:137:32
+   |
+LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
 error: transmute from a pointer to a pointer
-   --> $DIR/transmute.rs:172:29
-    |
-172 |         let _: *const f32 = std::mem::transmute(ptr);
-    |                             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32`
-    |
-    = note: `-D transmute-ptr-to-ptr` implied by `-D warnings`
+  --> $DIR/transmute.rs:169:29
+   |
+LL |         let _: *const f32 = std::mem::transmute(ptr);
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32`
+   |
+   = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
 
 error: transmute from a pointer to a pointer
-   --> $DIR/transmute.rs:173:27
-    |
-173 |         let _: *mut f32 = std::mem::transmute(mut_ptr);
-    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32`
+  --> $DIR/transmute.rs:170:27
+   |
+LL |         let _: *mut f32 = std::mem::transmute(mut_ptr);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32`
 
 error: transmute from a reference to a reference
-   --> $DIR/transmute.rs:175:23
-    |
-175 |         let _: &f32 = std::mem::transmute(&1u32);
-    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)`
+  --> $DIR/transmute.rs:172:23
+   |
+LL |         let _: &f32 = std::mem::transmute(&1u32);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)`
 
 error: transmute from a reference to a reference
-   --> $DIR/transmute.rs:176:23
-    |
-176 |         let _: &f64 = std::mem::transmute(&1f32);
-    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)`
+  --> $DIR/transmute.rs:173:23
+   |
+LL |         let _: &f64 = std::mem::transmute(&1f32);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)`
 
 error: transmute from a reference to a reference
-   --> $DIR/transmute.rs:179:27
-    |
-179 |         let _: &mut f32 = std::mem::transmute(&mut 1u32);
-    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`
+  --> $DIR/transmute.rs:176:27
+   |
+LL |         let _: &mut f32 = std::mem::transmute(&mut 1u32);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`
 
 error: transmute from a reference to a reference
-   --> $DIR/transmute.rs:180:37
-    |
-180 |         let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
-    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)`
+  --> $DIR/transmute.rs:177:37
+   |
+LL |         let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)`
 
 error: aborting due to 38 previous errors
 
index 08866c63ec6fde25d38327ea23bda3ac26f6d089..1b50133d3918f39ce2b224a6f0c5ad1cdc31de9b 100644 (file)
@@ -1,7 +1,5 @@
 //ignore-x86_64
 
-
-
 #[warn(wrong_transmute)]
 fn main() {
     unsafe {
index 65240c80a480d025e339f69fcb1318aeeba259d5..aee5152d6472e4ae2edbc9b75100f8ea69802c82 100644 (file)
@@ -1,9 +1,7 @@
 //ignore-x86
 //no-ignore-x86_64
 
-
-
-#[warn(wrong_transmute)]
+#[warn(clippy::wrong_transmute)]
 fn main() {
     unsafe {
         let _: *const usize = std::mem::transmute(6.0f64);
index 3a6a6e73f575e4044ae4038a2b0f4b75de87fae1..457050ec504b6f605e0ca518ccdc4dc85d173b7b 100644 (file)
@@ -1,15 +1,15 @@
 error: transmute from a `f64` to a pointer
--> $DIR/transmute_64bit.rs:9:31
-  |
-9 |         let _: *const usize = std::mem::transmute(6.0f64);
-  |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D wrong-transmute` implied by `-D warnings`
 --> $DIR/transmute_64bit.rs:7:31
+   |
+LL |         let _: *const usize = std::mem::transmute(6.0f64);
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::wrong-transmute` implied by `-D warnings`
 
 error: transmute from a `f64` to a pointer
-  --> $DIR/transmute_64bit.rs:11:29
+  --> $DIR/transmute_64bit.rs:9:29
    |
-11 |         let _: *mut usize = std::mem::transmute(6.0f64);
+LL |         let _: *mut usize = std::mem::transmute(6.0f64);
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/transmuting_null.rs b/tests/ui/transmuting_null.rs
new file mode 100644 (file)
index 0000000..ea3ee8e
--- /dev/null
@@ -0,0 +1,30 @@
+#![allow(dead_code)]
+#![warn(clippy::transmuting_null)]
+#![allow(clippy::zero_ptr)]
+#![allow(clippy::transmute_ptr_to_ref)]
+#![allow(clippy::eq_op)]
+
+// Easy to lint because these only span one line.
+fn one_liners() {
+    unsafe {
+        let _: &u64 = std::mem::transmute(0 as *const u64);
+        let _: &u64 = std::mem::transmute(std::ptr::null::<u64>());
+    }
+}
+
+pub const ZPTR: *const usize = 0 as *const _;
+pub const NOT_ZPTR: *const usize = 1 as *const _;
+
+fn transmute_const() {
+    unsafe {
+        // Should raise a lint.
+        let _: &u64 = std::mem::transmute(ZPTR);
+        // Should NOT raise a lint.
+        let _: &u64 = std::mem::transmute(NOT_ZPTR);
+    }
+}
+
+fn main() {
+    one_liners();
+    transmute_const();
+}
diff --git a/tests/ui/transmuting_null.stderr b/tests/ui/transmuting_null.stderr
new file mode 100644 (file)
index 0000000..05f91ee
--- /dev/null
@@ -0,0 +1,22 @@
+error: transmuting a known null pointer into a reference.
+  --> $DIR/transmuting_null.rs:10:23
+   |
+LL |         let _: &u64 = std::mem::transmute(0 as *const u64);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::transmuting-null` implied by `-D warnings`
+
+error: transmuting a known null pointer into a reference.
+  --> $DIR/transmuting_null.rs:11:23
+   |
+LL |         let _: &u64 = std::mem::transmute(std::ptr::null::<u64>());
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmuting a known null pointer into a reference.
+  --> $DIR/transmuting_null.rs:21:23
+   |
+LL |         let _: &u64 = std::mem::transmute(ZPTR);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index c6773add244305186f2b8657174633e260464ffe..c12d985650153a541988e6d86b5089c8cbe4a7d7 100644 (file)
@@ -1,4 +1,8 @@
-#![allow(many_single_char_names, blacklisted_name)]
+#![allow(
+    clippy::many_single_char_names,
+    clippy::blacklisted_name,
+    clippy::redundant_field_names
+)]
 
 #[derive(Copy, Clone)]
 struct Foo(u32);
 #[derive(Copy, Clone)]
 struct Bar([u8; 24]);
 
-type Baz = u32;
+#[derive(Copy, Clone)]
+pub struct Color {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+    pub a: u8,
+}
 
-fn good(a: &mut u32, b: u32, c: &Bar) {
+struct FooRef<'a> {
+    foo: &'a Foo,
 }
 
+type Baz = u32;
+
+fn good(a: &mut u32, b: u32, c: &Bar) {}
+
 fn good_return_implicit_lt_ref(foo: &Foo) -> &u32 {
     &foo.0
 }
 
-#[allow(needless_lifetimes)]
+#[allow(clippy::needless_lifetimes)]
 fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
     &foo.0
 }
 
-fn bad(x: &u32, y: &Foo, z: &Baz) {
+fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
+    FooRef { foo }
+}
+
+#[allow(clippy::needless_lifetimes)]
+fn good_return_explicit_lt_struct<'a>(foo: &'a Foo) -> FooRef<'a> {
+    FooRef { foo }
 }
 
+fn bad(x: &u32, y: &Foo, z: &Baz) {}
+
 impl Foo {
-    fn good(self, a: &mut u32, b: u32, c: &Bar) {
-    }
+    fn good(self, a: &mut u32, b: u32, c: &Bar) {}
 
-    fn good2(&mut self) {
-    }
+    fn good2(&mut self) {}
 
-    fn bad(&self, x: &u32, y: &Foo, z: &Baz) {
-    }
+    fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
 
-    fn bad2(x: &u32, y: &Foo, z: &Baz) {
-    }
+    fn bad2(x: &u32, y: &Foo, z: &Baz) {}
 }
 
 impl AsRef<u32> for Foo {
@@ -44,10 +63,22 @@ fn as_ref(&self) -> &u32 {
 }
 
 impl Bar {
-    fn good(&self, a: &mut u32, b: u32, c: &Bar) {
-    }
+    fn good(&self, a: &mut u32, b: u32, c: &Bar) {}
+
+    fn bad2(x: &u32, y: &Foo, z: &Baz) {}
+}
+
+trait MyTrait {
+    fn trait_method(&self, _foo: &Foo);
+}
+
+pub trait MyTrait2 {
+    fn trait_method2(&self, _color: &Color);
+}
 
-    fn bad2(x: &u32, y: &Foo, z: &Baz) {
+impl MyTrait for Foo {
+    fn trait_method(&self, _foo: &Foo) {
+        unimplemented!()
     }
 }
 
index db25cc5a02011b2a278ef7e580948c88a9dad3ab..754069b421cc9c2c78e9539872b14660db401e32 100644 (file)
@@ -1,82 +1,94 @@
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:23:11
+  --> $DIR/trivially_copy_pass_by_ref.rs:47:11
    |
-23 | fn bad(x: &u32, y: &Foo, z: &Baz) {
+LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
    |           ^^^^ help: consider passing by value instead: `u32`
    |
-   = note: `-D trivially-copy-pass-by-ref` implied by `-D warnings`
+   = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:23:20
+  --> $DIR/trivially_copy_pass_by_ref.rs:47:20
    |
-23 | fn bad(x: &u32, y: &Foo, z: &Baz) {
+LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
    |                    ^^^^ help: consider passing by value instead: `Foo`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:23:29
+  --> $DIR/trivially_copy_pass_by_ref.rs:47:29
    |
-23 | fn bad(x: &u32, y: &Foo, z: &Baz) {
+LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
    |                             ^^^^ help: consider passing by value instead: `Baz`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:33:12
+  --> $DIR/trivially_copy_pass_by_ref.rs:54:12
    |
-33 |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |            ^^^^^ help: consider passing by value instead: `self`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:33:22
+  --> $DIR/trivially_copy_pass_by_ref.rs:54:22
    |
-33 |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |                      ^^^^ help: consider passing by value instead: `u32`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:33:31
+  --> $DIR/trivially_copy_pass_by_ref.rs:54:31
    |
-33 |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |                               ^^^^ help: consider passing by value instead: `Foo`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:33:40
+  --> $DIR/trivially_copy_pass_by_ref.rs:54:40
    |
-33 |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |                                        ^^^^ help: consider passing by value instead: `Baz`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:36:16
+  --> $DIR/trivially_copy_pass_by_ref.rs:56:16
    |
-36 |     fn bad2(x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                ^^^^ help: consider passing by value instead: `u32`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:36:25
+  --> $DIR/trivially_copy_pass_by_ref.rs:56:25
    |
-36 |     fn bad2(x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                         ^^^^ help: consider passing by value instead: `Foo`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:36:34
+  --> $DIR/trivially_copy_pass_by_ref.rs:56:34
    |
-36 |     fn bad2(x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                                  ^^^^ help: consider passing by value instead: `Baz`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:50:16
+  --> $DIR/trivially_copy_pass_by_ref.rs:68:16
    |
-50 |     fn bad2(x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                ^^^^ help: consider passing by value instead: `u32`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:50:25
+  --> $DIR/trivially_copy_pass_by_ref.rs:68:25
    |
-50 |     fn bad2(x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                         ^^^^ help: consider passing by value instead: `Foo`
 
 error: this argument is passed by reference, but would be more efficient if passed by value
-  --> $DIR/trivially_copy_pass_by_ref.rs:50:34
+  --> $DIR/trivially_copy_pass_by_ref.rs:68:34
    |
-50 |     fn bad2(x: &u32, y: &Foo, z: &Baz) {
+LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                                  ^^^^ help: consider passing by value instead: `Baz`
 
-error: aborting due to 13 previous errors
+error: this argument is passed by reference, but would be more efficient if passed by value
+  --> $DIR/trivially_copy_pass_by_ref.rs:72:34
+   |
+LL |     fn trait_method(&self, _foo: &Foo);
+   |                                  ^^^^ help: consider passing by value instead: `Foo`
+
+error: this argument is passed by reference, but would be more efficient if passed by value
+  --> $DIR/trivially_copy_pass_by_ref.rs:76:37
+   |
+LL |     fn trait_method2(&self, _color: &Color);
+   |                                     ^^^^^^ help: consider passing by value instead: `Color`
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/ty_fn_sig.stderr b/tests/ui/ty_fn_sig.stderr
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed
new file mode 100644 (file)
index 0000000..a71a9ec
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+// should not warn on lossy casting in constant types
+// because not supported yet
+const C: i32 = 42;
+const C_I64: i64 = C as i64;
+
+fn main() {
+    // should suggest i64::from(c)
+    let c: i32 = 42;
+    let c_i64: i64 = i64::from(c);
+}
index 10d1c490ee6a04c34c3ee8d8d839bf7a26c14f44..6f48080ceddb7f023e3dd7a902b5031233a262b1 100644 (file)
@@ -1,10 +1,14 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
 // should not warn on lossy casting in constant types
 // because not supported yet
-const C : i32 = 42;
-const C_I64 : i64 = C as i64;
+const C: i32 = 42;
+const C_I64: i64 = C as i64;
 
 fn main() {
     // should suggest i64::from(c)
-    let c : i32 = 42;
-    let c_i64 : i64 = c as i64;
+    let c: i32 = 42;
+    let c_i64: i64 = c as i64;
 }
index b41bff7a9b06b3ad9ecf5b533961dbb06d0f018b..3b4f57a7a431b32a2ccca8f47d88cc6b2e2d058d 100644 (file)
@@ -1,10 +1,10 @@
-error: casting i32 to i64 may become silently lossy if types change
- --> $DIR/types.rs:9:23
-  |
-9 |     let c_i64 : i64 = c as i64;
-                        ^^^^^^^^ help: try: `i64::from(c)`
-  |
-  = note: `-D cast-lossless` implied by `-D warnings`
+error: casting i32 to i64 may become silently lossy if you later change the type
+  --> $DIR/types.rs:13:22
+   |
+LL |     let c_i64: i64 = c as i64;
+   |                      ^^^^^^^^ help: try: `i64::from(c)`
+   |
+   = note: `-D clippy::cast-lossless` implied by `-D warnings`
 
 error: aborting due to previous error
 
diff --git a/tests/ui/types_fn_to_int.rs b/tests/ui/types_fn_to_int.rs
deleted file mode 100644 (file)
index 8387586..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-enum Foo {
-    A(usize),
-    B
-}
-
-fn bar() -> i32 {
-    0i32
-}
-
-fn main() {
-    let x = Foo::A;
-    let _y = x as i32;
-    let _y1 = Foo::A as i32;
-    let _y = x as u32;
-    let _z = bar as u32;
-    let _y = bar as i64;
-    let _y = bar as u64;
-    let _z = Foo::A as i128;
-    let _z = Foo::A as u128;
-    let _z = bar as i128;
-    let _z = bar as u128;
-}
diff --git a/tests/ui/types_fn_to_int.stderr b/tests/ui/types_fn_to_int.stderr
deleted file mode 100644 (file)
index bbdf4ce..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-error: casting a `fn(usize) -> Foo {Foo::A}` to `i32` may truncate the function address value.
-  --> $DIR/types_fn_to_int.rs:12:14
-   |
-12 |     let _y = x as i32;
-   |              ^^^^^^^^ help: if you need the address of the function, consider: `x as usize`
-   |
-   = note: #[deny(fn_to_numeric_cast_with_truncation)] on by default
-
-error: casting a `fn(usize) -> Foo {Foo::A}` to `i32` may truncate the function address value.
-  --> $DIR/types_fn_to_int.rs:13:15
-   |
-13 |     let _y1 = Foo::A as i32;
-   |               ^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize`
-
-error: casting a `fn(usize) -> Foo {Foo::A}` to `u32` may truncate the function address value.
-  --> $DIR/types_fn_to_int.rs:14:14
-   |
-14 |     let _y = x as u32;
-   |              ^^^^^^^^ help: if you need the address of the function, consider: `x as usize`
-
-error: casting a `fn() -> i32 {bar}` to `u32` may truncate the function address value.
-  --> $DIR/types_fn_to_int.rs:15:14
-   |
-15 |     let _z = bar as u32;
-   |              ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize`
-
-error: casting a `fn() -> i32 {bar}` to `i64` may truncate the function address value.
-  --> $DIR/types_fn_to_int.rs:16:14
-   |
-16 |     let _y = bar as i64;
-   |              ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize`
-
-error: casting a `fn() -> i32 {bar}` to `u64` is bad style.
-  --> $DIR/types_fn_to_int.rs:17:14
-   |
-17 |     let _y = bar as u64;
-   |              ^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize`
-   |
-   = note: `-D fn-to-numeric-cast` implied by `-D warnings`
-
-error: casting a `fn(usize) -> Foo {Foo::A}` to `i128` is bad style.
-  --> $DIR/types_fn_to_int.rs:18:14
-   |
-18 |     let _z = Foo::A as i128;
-   |              ^^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize`
-
-error: casting a `fn(usize) -> Foo {Foo::A}` to `u128` is bad style.
-  --> $DIR/types_fn_to_int.rs:19:14
-   |
-19 |     let _z = Foo::A as u128;
-   |              ^^^^^^^^^^^^^^ help: if you need the address of the function, consider: `Foo::A as usize`
-
-error: casting a `fn() -> i32 {bar}` to `i128` is bad style.
-  --> $DIR/types_fn_to_int.rs:20:14
-   |
-20 |     let _z = bar as i128;
-   |              ^^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize`
-
-error: casting a `fn() -> i32 {bar}` to `u128` is bad style.
-  --> $DIR/types_fn_to_int.rs:21:14
-   |
-21 |     let _z = bar as u128;
-   |              ^^^^^^^^^^^ help: if you need the address of the function, consider: `bar as usize`
-
-error: aborting due to 10 previous errors
-
index 5bb0e7edfeda6e22806f4862fdd2bf6641b0cea5..27db9594f3b3305c7385ccea3506a22f534740f1 100644 (file)
@@ -1,22 +1,19 @@
-
-
-
-#[warn(zero_width_space)]
+#[warn(clippy::zero_width_space)]
 fn zero() {
     print!("Here >​< is a ZWS, and ​another");
     print!("This\u{200B}is\u{200B}fine");
 }
 
-#[warn(unicode_not_nfc)]
+#[warn(clippy::unicode_not_nfc)]
 fn canon() {
     print!("̀àh?");
-    print!("a\u{0300}h?"); // also okay
+    print!("a\u{0300}h?"); // also ok
 }
 
-#[warn(non_ascii_literal)]
+#[warn(clippy::non_ascii_literal)]
 fn uni() {
     print!("Üben!");
-    print!("\u{DC}ben!"); // this is okay
+    print!("\u{DC}ben!"); // this is ok
 }
 
 fn main() {
index 9e99a44bb60c17384c2d953cf418c52a8e00467a..c60dcdaec1d311ab4ecb6d7ba300dfbb6044dc3e 100644 (file)
@@ -1,30 +1,30 @@
 error: zero-width space detected
--> $DIR/unicode.rs:6:12
-  |
-6 |     print!("Here >​< is a ZWS, and ​another");
-  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D zero-width-space` implied by `-D warnings`
-  = help: Consider replacing the string with:
-          ""Here >/u{200B}< is a ZWS, and /u{200B}another""
 --> $DIR/unicode.rs:3:12
+   |
+LL |     print!("Here >​< is a ZWS, and ​another");
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::zero-width-space` implied by `-D warnings`
+   = help: Consider replacing the string with:
+           ""Here >/u{200B}< is a ZWS, and /u{200B}another""
 
 error: non-nfc unicode sequence detected
-  --> $DIR/unicode.rs:12:12
+  --> $DIR/unicode.rs:9:12
    |
-12 |     print!("̀àh?");
+LL |     print!("̀àh?");
    |            ^^^^^
    |
-   = note: `-D unicode-not-nfc` implied by `-D warnings`
+   = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
    = help: Consider replacing the string with:
            ""̀àh?""
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:18:12
+  --> $DIR/unicode.rs:15:12
    |
-18 |     print!("Üben!");
+LL |     print!("Üben!");
    |            ^^^^^^^
    |
-   = note: `-D non-ascii-literal` implied by `-D warnings`
+   = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
    = help: Consider replacing the string with:
            ""/u{dc}ben!""
 
diff --git a/tests/ui/unit_arg.fixed b/tests/ui/unit_arg.fixed
new file mode 100644 (file)
index 0000000..cf146c9
--- /dev/null
@@ -0,0 +1,64 @@
+// run-rustfix
+#![warn(clippy::unit_arg)]
+#![allow(clippy::no_effect, unused_must_use)]
+
+use std::fmt::Debug;
+
+fn foo<T: Debug>(t: T) {
+    println!("{:?}", t);
+}
+
+fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) {
+    println!("{:?}, {:?}, {:?}", t1, t2, t3);
+}
+
+struct Bar;
+
+impl Bar {
+    fn bar<T: Debug>(&self, t: T) {
+        println!("{:?}", t);
+    }
+}
+
+fn bad() {
+    foo(());
+    foo(());
+    foo(());
+    foo(());
+    foo3((), 2, 2);
+    let b = Bar;
+    b.bar(());
+}
+
+fn ok() {
+    foo(());
+    foo(1);
+    foo({ 1 });
+    foo3("a", 3, vec![3]);
+    let b = Bar;
+    b.bar({ 1 });
+    b.bar(());
+    question_mark();
+}
+
+fn question_mark() -> Result<(), ()> {
+    Ok(Ok(())?)?;
+    Ok(Ok(()))??;
+    Ok(())
+}
+
+#[allow(dead_code)]
+mod issue_2945 {
+    fn unit_fn() -> Result<(), i32> {
+        Ok(())
+    }
+
+    fn fallible() -> Result<(), i32> {
+        Ok(unit_fn()?)
+    }
+}
+
+fn main() {
+    bad();
+    ok();
+}
index 8f290446b5e42a990fec717fbc0ed1e3a0861773..c15b0a50045565b691a751af079e54211030e052 100644 (file)
@@ -1,5 +1,6 @@
-#![warn(unit_arg)]
-#![allow(no_effect)]
+// run-rustfix
+#![warn(clippy::unit_arg)]
+#![allow(clippy::no_effect, unused_must_use)]
 
 use std::fmt::Debug;
 
@@ -21,7 +22,9 @@ fn bar<T: Debug>(&self, t: T) {
 
 fn bad() {
     foo({});
-    foo({ 1; });
+    foo({
+        1;
+    });
     foo(foo(1));
     foo({
         foo(1);
@@ -29,7 +32,9 @@ fn bad() {
     });
     foo3({}, 2, 2);
     let b = Bar;
-    b.bar({ 1; });
+    b.bar({
+        1;
+    });
 }
 
 fn ok() {
@@ -49,6 +54,17 @@ fn question_mark() -> Result<(), ()> {
     Ok(())
 }
 
+#[allow(dead_code)]
+mod issue_2945 {
+    fn unit_fn() -> Result<(), i32> {
+        Ok(())
+    }
+
+    fn fallible() -> Result<(), i32> {
+        Ok(unit_fn()?)
+    }
+}
+
 fn main() {
     bad();
     ok();
index ca48f39263bf5539b33f02441c1e80cb15561893..862534b18ecbb20c0e89f260e070a71b8890dc1b 100644 (file)
@@ -1,67 +1,73 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:23:9
+  --> $DIR/unit_arg.rs:24:9
    |
-23 |     foo({});
+LL |     foo({});
    |         ^^
    |
-   = note: `-D unit-arg` implied by `-D warnings`
+   = note: `-D clippy::unit-arg` implied by `-D warnings`
 help: if you intended to pass a unit value, use a unit literal instead
    |
-23 |     foo(());
+LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:24:9
+  --> $DIR/unit_arg.rs:25:9
    |
-24 |     foo({ 1; });
-   |         ^^^^^^
+LL |       foo({
+   |  _________^
+LL | |         1;
+LL | |     });
+   | |_____^
 help: if you intended to pass a unit value, use a unit literal instead
    |
-24 |     foo(());
+LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:25:9
+  --> $DIR/unit_arg.rs:28:9
    |
-25 |     foo(foo(1));
+LL |     foo(foo(1));
    |         ^^^^^^
 help: if you intended to pass a unit value, use a unit literal instead
    |
-25 |     foo(());
+LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:26:9
+  --> $DIR/unit_arg.rs:29:9
    |
-26 |       foo({
+LL |       foo({
    |  _________^
-27 | |         foo(1);
-28 | |         foo(2);
-29 | |     });
+LL | |         foo(1);
+LL | |         foo(2);
+LL | |     });
    | |_____^
 help: if you intended to pass a unit value, use a unit literal instead
    |
-26 |     foo(());
+LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:30:10
+  --> $DIR/unit_arg.rs:33:10
    |
-30 |     foo3({}, 2, 2);
+LL |     foo3({}, 2, 2);
    |          ^^
 help: if you intended to pass a unit value, use a unit literal instead
    |
-30 |     foo3((), 2, 2);
+LL |     foo3((), 2, 2);
    |          ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:32:11
+  --> $DIR/unit_arg.rs:35:11
    |
-32 |     b.bar({ 1; });
-   |           ^^^^^^
+LL |       b.bar({
+   |  ___________^
+LL | |         1;
+LL | |     });
+   | |_____^
 help: if you intended to pass a unit value, use a unit literal instead
    |
-32 |     b.bar(());
+LL |     b.bar(());
    |           ^^
 
 error: aborting due to 6 previous errors
index 2b6d757845fe156d9c2a05f6490faa026d60fc73..48c22f7f875a781e209eb9175066e3fb8df9021a 100644 (file)
@@ -1,21 +1,23 @@
-
-
-
-#![warn(unit_cmp)]
-#![allow(no_effect, unnecessary_operation)]
+#![warn(clippy::unit_cmp)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation)]
 
 #[derive(PartialEq)]
 pub struct ContainsUnit(()); // should be fine
 
 fn main() {
     // this is fine
-    if true == false {
-    }
+    if true == false {}
 
     // this warns
-    if { true; } == { false; } {
-    }
+    if {
+        true;
+    } == {
+        false;
+    } {}
 
-    if { true; } > { false; } {
-    }
+    if {
+        true;
+    } > {
+        false;
+    } {}
 }
index 51ad3fca94793772efb38f3a3cc11ae09e4888a5..56293403043d6987eae8d8b921318ce1a5b02d42 100644 (file)
@@ -1,16 +1,26 @@
 error: ==-comparison of unit values detected. This will always be true
-  --> $DIR/unit_cmp.rs:16:8
+  --> $DIR/unit_cmp.rs:12:8
    |
-16 |     if { true; } == { false; } {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^
+LL |       if {
+   |  ________^
+LL | |         true;
+LL | |     } == {
+LL | |         false;
+LL | |     } {}
+   | |_____^
    |
-   = note: `-D unit-cmp` implied by `-D warnings`
+   = note: `-D clippy::unit-cmp` implied by `-D warnings`
 
 error: >-comparison of unit values detected. This will always be false
-  --> $DIR/unit_cmp.rs:19:8
+  --> $DIR/unit_cmp.rs:18:8
    |
-19 |     if { true; } > { false; } {
-   |        ^^^^^^^^^^^^^^^^^^^^^^
+LL |       if {
+   |  ________^
+LL | |         true;
+LL | |     } > {
+LL | |         false;
+LL | |     } {}
+   | |_____^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/unknown_attribute.rs b/tests/ui/unknown_attribute.rs
new file mode 100644 (file)
index 0000000..e993e63
--- /dev/null
@@ -0,0 +1,3 @@
+#[clippy::unknown]
+#[clippy::cognitive_complexity = "1"]
+fn main() {}
diff --git a/tests/ui/unknown_attribute.stderr b/tests/ui/unknown_attribute.stderr
new file mode 100644 (file)
index 0000000..47e37ae
--- /dev/null
@@ -0,0 +1,8 @@
+error: Usage of unknown attribute
+  --> $DIR/unknown_attribute.rs:1:11
+   |
+LL | #[clippy::unknown]
+   |           ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/unknown_clippy_lints.rs b/tests/ui/unknown_clippy_lints.rs
new file mode 100644 (file)
index 0000000..0a93c81
--- /dev/null
@@ -0,0 +1,5 @@
+#![allow(clippy::All)]
+#![warn(clippy::pedantic)]
+
+#[warn(clippy::if_not_els)]
+fn main() {}
diff --git a/tests/ui/unknown_clippy_lints.stderr b/tests/ui/unknown_clippy_lints.stderr
new file mode 100644 (file)
index 0000000..3c86432
--- /dev/null
@@ -0,0 +1,16 @@
+error: unknown clippy lint: clippy::if_not_els
+  --> $DIR/unknown_clippy_lints.rs:4:8
+   |
+LL | #[warn(clippy::if_not_els)]
+   |        ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unknown-clippy-lints` implied by `-D warnings`
+
+error: unknown clippy lint: clippy::All
+  --> $DIR/unknown_clippy_lints.rs:1:10
+   |
+LL | #![allow(clippy::All)]
+   |          ^^^^^^^^^^^ help: lowercase the lint name: `all`
+
+error: aborting due to 2 previous errors
+
index 96166ed4f139aa5c2e518bbbaa13f983d4772cdf..570536d0a56f5cee0a544dcbb181f369151ccfe5 100644 (file)
@@ -1,6 +1,7 @@
-#![warn(clone_on_ref_ptr)]
+#![warn(clippy::clone_on_ref_ptr)]
 #![allow(unused)]
 
+use std::cell::RefCell;
 use std::collections::HashSet;
 use std::collections::VecDeque;
 use std::rc::{self, Rc};
@@ -18,6 +19,9 @@ fn clone_on_copy() {
     vec![1].clone(); // ok, not a Copy type
     Some(vec![1]).clone(); // ok, not a Copy type
     (&42).clone();
+
+    let rc = RefCell::new(0);
+    rc.borrow().clone();
 }
 
 fn clone_on_ref_ptr() {
@@ -40,7 +44,7 @@ fn clone_on_ref_ptr() {
     sync::Weak::clone(&arc_weak);
 
     let x = Arc::new(SomeImpl);
-    let _: Arc<SomeTrait> = x.clone(); 
+    let _: Arc<SomeTrait> = x.clone();
 }
 
 fn clone_on_copy_generic<T: Copy>(t: T) {
@@ -54,12 +58,60 @@ fn clone_on_double_ref() {
     let y = &&x;
     let z: &Vec<_> = y.clone();
 
-    println!("{:p} {:p}",*y, z);
+    println!("{:p} {:p}", *y, z);
 }
 
 fn iter_clone_collect() {
-    let v = [1,2,3,4,5];
-    let v2 : Vec<isize> = v.iter().cloned().collect();
-    let v3 : HashSet<isize> = v.iter().cloned().collect();
-    let v4 : VecDeque<isize> = v.iter().cloned().collect();
+    let v = [1, 2, 3, 4, 5];
+    let v2: Vec<isize> = v.iter().cloned().collect();
+    let v3: HashSet<isize> = v.iter().cloned().collect();
+    let v4: VecDeque<isize> = v.iter().cloned().collect();
+
+    // Handle macro expansion in suggestion
+    let _: Vec<isize> = vec![1, 2, 3].iter().cloned().collect();
+
+    // Issue #3704
+    unsafe {
+        let _: Vec<u8> = std::ffi::CStr::from_ptr(std::ptr::null())
+            .to_bytes()
+            .iter()
+            .cloned()
+            .collect();
+    }
+}
+
+mod many_derefs {
+    struct A;
+    struct B;
+    struct C;
+    struct D;
+    #[derive(Copy, Clone)]
+    struct E;
+
+    macro_rules! impl_deref {
+        ($src:ident, $dst:ident) => {
+            impl std::ops::Deref for $src {
+                type Target = $dst;
+                fn deref(&self) -> &Self::Target {
+                    &$dst
+                }
+            }
+        };
+    }
+
+    impl_deref!(A, B);
+    impl_deref!(B, C);
+    impl_deref!(C, D);
+    impl std::ops::Deref for D {
+        type Target = &'static E;
+        fn deref(&self) -> &Self::Target {
+            &&E
+        }
+    }
+
+    fn go1() {
+        let a = A;
+        let _: E = a.clone();
+        let _: E = *****a;
+    }
 }
index 3c1ce9080229cc5b5c130cad57b25a6000338344..a014478597fc3406fed86b6d30ac5e3c8909457d 100644 (file)
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:16:5
+  --> $DIR/unnecessary_clone.rs:17:5
    |
-16 |     42.clone();
+LL |     42.clone();
    |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
    |
-   = note: `-D clone-on-copy` implied by `-D warnings`
+   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:20:5
+  --> $DIR/unnecessary_clone.rs:21:5
    |
-20 |     (&42).clone();
+LL |     (&42).clone();
    |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
 
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:24:5
+   |
+LL |     rc.borrow().clone();
+   |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
+
 error: using '.clone()' on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:30:5
+  --> $DIR/unnecessary_clone.rs:34:5
    |
-30 |     rc.clone();
+LL |     rc.clone();
    |     ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
    |
-   = note: `-D clone-on-ref-ptr` implied by `-D warnings`
+   = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
 
 error: using '.clone()' on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:33:5
+  --> $DIR/unnecessary_clone.rs:37:5
    |
-33 |     arc.clone();
+LL |     arc.clone();
    |     ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
 
 error: using '.clone()' on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:36:5
+  --> $DIR/unnecessary_clone.rs:40:5
    |
-36 |     rcweak.clone();
+LL |     rcweak.clone();
    |     ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
 
 error: using '.clone()' on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:39:5
+  --> $DIR/unnecessary_clone.rs:43:5
    |
-39 |     arc_weak.clone();
+LL |     arc_weak.clone();
    |     ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
 
 error: using '.clone()' on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:43:29
+  --> $DIR/unnecessary_clone.rs:47:29
    |
-43 |     let _: Arc<SomeTrait> = x.clone(); 
+LL |     let _: Arc<SomeTrait> = x.clone();
    |                             ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:47:5
+  --> $DIR/unnecessary_clone.rs:51:5
    |
-47 |     t.clone();
+LL |     t.clone();
    |     ^^^^^^^^^ help: try removing the `clone` call: `t`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:49:5
+  --> $DIR/unnecessary_clone.rs:53:5
    |
-49 |     Some(t).clone();
+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:55:22
+  --> $DIR/unnecessary_clone.rs:59:22
    |
-55 |     let z: &Vec<_> = y.clone();
+LL |     let z: &Vec<_> = y.clone();
    |                      ^^^^^^^^^
    |
-   = note: #[deny(clone_double_ref)] on by default
+   = note: #[deny(clippy::clone_double_ref)] on by default
 help: try dereferencing it
    |
-55 |     let z: &Vec<_> = &(*y).clone();
+LL |     let z: &Vec<_> = &(*y).clone();
    |                      ^^^^^^^^^^^^^
 help: or try being explicit about what type to clone
    |
-55 |     let z: &Vec<_> = &std::vec::Vec<i32>::clone(y);
+LL |     let z: &Vec<_> = &std::vec::Vec<i32>::clone(y);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: called `cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
-  --> $DIR/unnecessary_clone.rs:62:27
+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
    |
-62 |     let v2 : Vec<isize> = v.iter().cloned().collect();
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let v2: Vec<isize> = v.iter().cloned().collect();
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+   |
+   = 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
+   |
+LL |     let _: Vec<isize> = 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
+   |
+LL |               .to_bytes()
+   |  ________________________^
+LL | |             .iter()
+LL | |             .cloned()
+LL | |             .collect();
+   | |______________________^ help: try: `.to_vec()`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/unnecessary_clone.rs:114:20
    |
-   = note: `-D iter-cloned-collect` implied by `-D warnings`
+LL |         let _: E = a.clone();
+   |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
 
-error: aborting due to 11 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/unnecessary_filter_map.rs b/tests/ui/unnecessary_filter_map.rs
new file mode 100644 (file)
index 0000000..af858e4
--- /dev/null
@@ -0,0 +1,17 @@
+fn main() {
+    let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None });
+    let _ = (0..4).filter_map(|x| {
+        if x > 1 {
+            return Some(x);
+        };
+        None
+    });
+    let _ = (0..4).filter_map(|x| match x {
+        0 | 1 => None,
+        _ => Some(x),
+    });
+
+    let _ = (0..4).filter_map(|x| Some(x + 1));
+
+    let _ = (0..4).filter_map(i32::checked_abs);
+}
diff --git a/tests/ui/unnecessary_filter_map.stderr b/tests/ui/unnecessary_filter_map.stderr
new file mode 100644 (file)
index 0000000..041829c
--- /dev/null
@@ -0,0 +1,38 @@
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:2:13
+   |
+LL |     let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None });
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnecessary-filter-map` implied by `-D warnings`
+
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:3:13
+   |
+LL |       let _ = (0..4).filter_map(|x| {
+   |  _____________^
+LL | |         if x > 1 {
+LL | |             return Some(x);
+LL | |         };
+LL | |         None
+LL | |     });
+   | |______^
+
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:9:13
+   |
+LL |       let _ = (0..4).filter_map(|x| match x {
+   |  _____________^
+LL | |         0 | 1 => None,
+LL | |         _ => Some(x),
+LL | |     });
+   | |______^
+
+error: this `.filter_map` can be written more simply using `.map`
+  --> $DIR/unnecessary_filter_map.rs:14:13
+   |
+LL |     let _ = (0..4).filter_map(|x| Some(x + 1));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed
new file mode 100644 (file)
index 0000000..5f12d72
--- /dev/null
@@ -0,0 +1,44 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+/// Calls which should trigger the `UNNECESSARY_FOLD` lint
+fn unnecessary_fold() {
+    // Can be replaced by .any
+    let _ = (0..3).any(|x| x > 2);
+    // Can be replaced by .all
+    let _ = (0..3).all(|x| x > 2);
+    // Can be replaced by .sum
+    let _: i32 = (0..3).sum();
+    // Can be replaced by .product
+    let _: i32 = (0..3).product();
+}
+
+/// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)`
+fn unnecessary_fold_span_for_multi_element_chain() {
+    let _: bool = (0..3).map(|x| 2 * x).any(|x| x > 2);
+}
+
+/// Calls which should not trigger the `UNNECESSARY_FOLD` lint
+fn unnecessary_fold_should_ignore() {
+    let _ = (0..3).fold(true, |acc, x| acc || x > 2);
+    let _ = (0..3).fold(false, |acc, x| acc && x > 2);
+    let _ = (0..3).fold(1, |acc, x| acc + x);
+    let _ = (0..3).fold(0, |acc, x| acc * x);
+    let _ = (0..3).fold(0, |acc, x| 1 + acc + x);
+
+    // We only match against an accumulator on the left
+    // hand side. We could lint for .sum and .product when
+    // it's on the right, but don't for now (and this wouldn't
+    // be valid if we extended the lint to cover arbitrary numeric
+    // types).
+    let _ = (0..3).fold(false, |acc, x| x > 2 || acc);
+    let _ = (0..3).fold(true, |acc, x| x > 2 && acc);
+    let _ = (0..3).fold(0, |acc, x| x + acc);
+    let _ = (0..3).fold(1, |acc, x| x * acc);
+
+    let _ = [(0..2), (0..3)].iter().fold(0, |a, b| a + b.len());
+    let _ = [(0..2), (0..3)].iter().fold(1, |a, b| a * b.len());
+}
+
+fn main() {}
index 62198e21ef7ce7ca4fb5449cd108472aef35b948..ae667d1ac06326660af6ff5fb148c5fe5f757f49 100644 (file)
@@ -1,3 +1,7 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
 /// Calls which should trigger the `UNNECESSARY_FOLD` lint
 fn unnecessary_fold() {
     // Can be replaced by .any
@@ -5,14 +9,14 @@ fn unnecessary_fold() {
     // Can be replaced by .all
     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
     // Can be replaced by .sum
-    let _ = (0..3).fold(0, |acc, x| acc + x);
+    let _: i32 = (0..3).fold(0, |acc, x| acc + x);
     // Can be replaced by .product
-    let _ = (0..3).fold(1, |acc, x| acc * x);
+    let _: i32 = (0..3).fold(1, |acc, x| acc * x);
 }
 
 /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)`
 fn unnecessary_fold_span_for_multi_element_chain() {
-    let _ = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
+    let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
 }
 
 /// Calls which should not trigger the `UNNECESSARY_FOLD` lint
index 8bc4b8244bd55b28ee29cf5e5b6b3468149f7684..f9911d4a3dcbef05116df8587f811ea35d492de1 100644 (file)
@@ -1,34 +1,34 @@
 error: this `.fold` can be written more succinctly using another method
--> $DIR/unnecessary_fold.rs:4:19
-  |
-4 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
-  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
-  |
-  = note: `-D unnecessary-fold` implied by `-D warnings`
 --> $DIR/unnecessary_fold.rs:8:19
+   |
+LL |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
+   |
+   = note: `-D clippy::unnecessary-fold` implied by `-D warnings`
 
 error: this `.fold` can be written more succinctly using another method
--> $DIR/unnecessary_fold.rs:6:19
-  |
-6 |     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
-  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)`
 --> $DIR/unnecessary_fold.rs:10:19
+   |
+LL |     let _ = (0..3).fold(true, |acc, x| acc && x > 2);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.all(|x| x > 2)`
 
 error: this `.fold` can be written more succinctly using another method
- --> $DIR/unnecessary_fold.rs:8:19
-  |
-8 |     let _ = (0..3).fold(0, |acc, x| acc + x);
-  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.sum()`
+  --> $DIR/unnecessary_fold.rs:12:24
+   |
+LL |     let _: i32 = (0..3).fold(0, |acc, x| acc + x);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.sum()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:10:19
+  --> $DIR/unnecessary_fold.rs:14:24
    |
-10 |     let _ = (0..3).fold(1, |acc, x| acc * x);
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.product()`
+LL |     let _: i32 = (0..3).fold(1, |acc, x| acc * x);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.product()`
 
 error: this `.fold` can be written more succinctly using another method
-  --> $DIR/unnecessary_fold.rs:15:34
+  --> $DIR/unnecessary_fold.rs:19:40
    |
-15 |     let _ = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
+LL |     let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2);
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/unnecessary_operation.rs b/tests/ui/unnecessary_operation.rs
new file mode 100644 (file)
index 0000000..3c6796f
--- /dev/null
@@ -0,0 +1,77 @@
+#![feature(box_syntax)]
+#![allow(clippy::deref_addrof)]
+#![warn(clippy::unnecessary_operation)]
+
+struct Tuple(i32);
+struct Struct {
+    field: i32,
+}
+enum Enum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+struct DropStruct {
+    field: i32,
+}
+impl Drop for DropStruct {
+    fn drop(&mut self) {}
+}
+struct DropTuple(i32);
+impl Drop for DropTuple {
+    fn drop(&mut self) {}
+}
+enum DropEnum {
+    Tuple(i32),
+    Struct { field: i32 },
+}
+impl Drop for DropEnum {
+    fn drop(&mut self) {}
+}
+struct FooString {
+    s: String,
+}
+
+fn get_number() -> i32 {
+    0
+}
+fn get_struct() -> Struct {
+    Struct { field: 0 }
+}
+fn get_drop_struct() -> DropStruct {
+    DropStruct { field: 0 }
+}
+
+fn main() {
+    Tuple(get_number());
+    Struct { field: get_number() };
+    Struct { ..get_struct() };
+    Enum::Tuple(get_number());
+    Enum::Struct { field: get_number() };
+    5 + get_number();
+    *&get_number();
+    &get_number();
+    (5, 6, get_number());
+    box get_number();
+    get_number()..;
+    ..get_number();
+    5..get_number();
+    [42, get_number()];
+    [42, 55][get_number() as usize];
+    (42, get_number()).1;
+    [get_number(); 55];
+    [42; 55][get_number() as usize];
+    {
+        get_number()
+    };
+    FooString {
+        s: String::from("blah"),
+    };
+
+    // Do not warn
+    DropTuple(get_number());
+    DropStruct { field: get_number() };
+    DropStruct { field: get_number() };
+    DropStruct { ..get_drop_struct() };
+    DropEnum::Tuple(get_number());
+    DropEnum::Struct { field: get_number() };
+}
diff --git a/tests/ui/unnecessary_operation.stderr b/tests/ui/unnecessary_operation.stderr
new file mode 100644 (file)
index 0000000..826bf6e
--- /dev/null
@@ -0,0 +1,128 @@
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:45:5
+   |
+LL |     Tuple(get_number());
+   |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+   |
+   = note: `-D clippy::unnecessary-operation` implied by `-D warnings`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:46:5
+   |
+LL |     Struct { field: get_number() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:47:5
+   |
+LL |     Struct { ..get_struct() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_struct();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:48:5
+   |
+LL |     Enum::Tuple(get_number());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:49:5
+   |
+LL |     Enum::Struct { field: get_number() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:50:5
+   |
+LL |     5 + get_number();
+   |     ^^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:51:5
+   |
+LL |     *&get_number();
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:52:5
+   |
+LL |     &get_number();
+   |     ^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:53:5
+   |
+LL |     (5, 6, get_number());
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `5;6;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:54:5
+   |
+LL |     box get_number();
+   |     ^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:55:5
+   |
+LL |     get_number()..;
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:56:5
+   |
+LL |     ..get_number();
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:57:5
+   |
+LL |     5..get_number();
+   |     ^^^^^^^^^^^^^^^^ help: replace it with: `5;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:58:5
+   |
+LL |     [42, get_number()];
+   |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:59:5
+   |
+LL |     [42, 55][get_number() as usize];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42, 55];get_number() as usize;`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:60:5
+   |
+LL |     (42, get_number()).1;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `42;get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:61:5
+   |
+LL |     [get_number(); 55];
+   |     ^^^^^^^^^^^^^^^^^^^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:62:5
+   |
+LL |     [42; 55][get_number() as usize];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `[42; 55];get_number() as usize;`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:63:5
+   |
+LL | /     {
+LL | |         get_number()
+LL | |     };
+   | |______^ help: replace it with: `get_number();`
+
+error: statement can be reduced
+  --> $DIR/unnecessary_operation.rs:66:5
+   |
+LL | /     FooString {
+LL | |         s: String::from("blah"),
+LL | |     };
+   | |______^ help: replace it with: `String::from("blah");`
+
+error: aborting due to 20 previous errors
+
diff --git a/tests/ui/unnecessary_ref.fixed b/tests/ui/unnecessary_ref.fixed
new file mode 100644 (file)
index 0000000..f7b9411
--- /dev/null
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![feature(stmt_expr_attributes)]
+#![allow(unused_variables)]
+
+struct Outer {
+    inner: u32,
+}
+
+#[deny(clippy::ref_in_deref)]
+fn main() {
+    let outer = Outer { inner: 0 };
+    let inner = outer.inner;
+}
index 53b970dfa72c30b4ecc3bf233b88f8b7e9340e88..4e585b9b96ba9461aaf082f014f5570177b11cce 100644 (file)
@@ -1,11 +1,13 @@
-#![feature(tool_attributes)]
+// run-rustfix
+
 #![feature(stmt_expr_attributes)]
+#![allow(unused_variables)]
 
 struct Outer {
     inner: u32,
 }
 
-#[deny(ref_in_deref)]
+#[deny(clippy::ref_in_deref)]
 fn main() {
     let outer = Outer { inner: 0 };
     let inner = (&outer).inner;
index ffc65084afa6149f24182952ab37912a6d01447b..89adca3b1ad7539902cd13a6f4c055827fc63053 100644 (file)
@@ -1,14 +1,14 @@
 error: Creating a reference that is immediately dereferenced.
-  --> $DIR/unnecessary_ref.rs:11:17
+  --> $DIR/unnecessary_ref.rs:13:17
    |
-11 |     let inner = (&outer).inner;
-   |                 ^^^^^^^^ help: try this: `outer.inner`
+LL |     let inner = (&outer).inner;
+   |                 ^^^^^^^^ help: try this: `outer`
    |
 note: lint level defined here
-  --> $DIR/unnecessary_ref.rs:8:8
+  --> $DIR/unnecessary_ref.rs:10:8
    |
-8  | #[deny(ref_in_deref)]
-   |        ^^^^^^^^^^^^
+LL | #[deny(clippy::ref_in_deref)]
+   |        ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 8c9606022642eeddc588eeb8b5721baf62820fcc..fa639aa70d61d8574335e1a22399a65c641eb3fb 100644 (file)
@@ -1,7 +1,4 @@
-
-
-
-#![warn(unneeded_field_pattern)]
+#![warn(clippy::unneeded_field_pattern)]
 #[allow(dead_code, unused)]
 
 struct Foo {
@@ -14,13 +11,12 @@ fn main() {
     let f = Foo { a: 0, b: 0, c: 0 };
 
     match f {
-        Foo { a: _, b: 0, .. } => {}
-
-        Foo { a: _, b: _, c: _ } => {}
+        Foo { a: _, b: 0, .. } => {},
 
+        Foo { a: _, b: _, c: _ } => {},
     }
     match f {
-        Foo { b: 0, .. } => {} // should be OK
-        Foo { .. } => {} // and the Force might be with this one
+        Foo { b: 0, .. } => {}, // should be OK
+        Foo { .. } => {},       // and the Force might be with this one
     }
 }
index 7e4c3a6cb9cb5e07ecfaff789dd91d40a3414d62..e7b92ce1e197b3631cede7d5fb7090260f54f87f 100644 (file)
@@ -1,16 +1,16 @@
 error: You matched a field with a wildcard pattern. Consider using `..` instead
-  --> $DIR/unneeded_field_pattern.rs:17:15
+  --> $DIR/unneeded_field_pattern.rs:14:15
    |
-17 |         Foo { a: _, b: 0, .. } => {}
+LL |         Foo { a: _, b: 0, .. } => {},
    |               ^^^^
    |
-   = note: `-D unneeded-field-pattern` implied by `-D warnings`
+   = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings`
    = help: Try with `Foo { b: 0, .. }`
 
 error: All the struct fields are matched to a wildcard pattern, consider using `..`.
-  --> $DIR/unneeded_field_pattern.rs:19:9
+  --> $DIR/unneeded_field_pattern.rs:16:9
    |
-19 |         Foo { a: _, b: _, c: _ } => {}
+LL |         Foo { a: _, b: _, c: _ } => {},
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: Try with `Foo { .. }` instead
diff --git a/tests/ui/unreadable_literal.fixed b/tests/ui/unreadable_literal.fixed
new file mode 100644 (file)
index 0000000..1fc93b9
--- /dev/null
@@ -0,0 +1,25 @@
+// run-rustfix
+
+#[warn(clippy::unreadable_literal)]
+#[allow(unused_variables)]
+fn main() {
+    let good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        65536,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
+    let bad = (0b11_0110_i64, 0x0123_4567_8901_usize, 123_456_f32, 1.234_567_f32);
+    let good_sci = 1.1234e1;
+    let bad_sci = 1.123_456e1;
+
+    let fail9 = 0x00ab_cdef;
+    let fail10: u32 = 0xBAFE_BAFE;
+    let fail11 = 0x0abc_deff;
+    let fail12: i128 = 0x00ab_cabc_abca_bcab_cabc;
+}
index 0ec757cfbcfe5fb8bd3dd8b7c6e206ed7ab90b55..ef0ef2b9b9e5216e7cccda3dd5f63ac5a57ef618 100644 (file)
@@ -1,10 +1,25 @@
+// run-rustfix
 
-
-#[warn(unreadable_literal)]
+#[warn(clippy::unreadable_literal)]
 #[allow(unused_variables)]
 fn main() {
-    let good = (0b1011_i64, 0o1_234_u32, 0x1_234_567, 65536, 1_2345_6789, 1234_f32, 1_234.12_f32, 1_234.123_f32, 1.123_4_f32);
+    let good = (
+        0b1011_i64,
+        0o1_234_u32,
+        0x1_234_567,
+        65536,
+        1_2345_6789,
+        1234_f32,
+        1_234.12_f32,
+        1_234.123_f32,
+        1.123_4_f32,
+    );
     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
     let good_sci = 1.1234e1;
     let bad_sci = 1.123456e1;
+
+    let fail9 = 0xabcdef;
+    let fail10: u32 = 0xBAFEBAFE;
+    let fail11 = 0xabcdeff;
+    let fail12: i128 = 0xabcabcabcabcabcabc;
 }
index cffcad1eef7b2b92b050f2de02d8bf9957b703f8..2ece537828751ff13a3988548504668b810079d7 100644 (file)
@@ -1,34 +1,58 @@
 error: long literal lacking separators
--> $DIR/unreadable_literal.rs:7:16
-  |
-7 |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
-  |                ^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
-  |
-  = note: `-D unreadable-literal` implied by `-D warnings`
 --> $DIR/unreadable_literal.rs:17:16
+   |
+LL |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
+   |                ^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
+   |
+   = note: `-D clippy::unreadable-literal` implied by `-D warnings`
 
 error: long literal lacking separators
--> $DIR/unreadable_literal.rs:7:30
-  |
-7 |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
-  |                              ^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
 --> $DIR/unreadable_literal.rs:17:30
+   |
+LL |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
+   |                              ^^^^^^^^^^^^^^^^^^^ help: consider: `0x0123_4567_8901_usize`
 
 error: long literal lacking separators
--> $DIR/unreadable_literal.rs:7:51
-  |
-7 |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
-  |                                                   ^^^^^^^^^^ help: consider: `123_456_f32`
 --> $DIR/unreadable_literal.rs:17:51
+   |
+LL |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
+   |                                                   ^^^^^^^^^^ help: consider: `123_456_f32`
 
 error: long literal lacking separators
--> $DIR/unreadable_literal.rs:7:63
-  |
-7 |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
-  |                                                               ^^^^^^^^^^^^ help: consider: `1.234_567_f32`
 --> $DIR/unreadable_literal.rs:17:63
+   |
+LL |     let bad = (0b110110_i64, 0x12345678901_usize, 123456_f32, 1.234567_f32);
+   |                                                               ^^^^^^^^^^^^ help: consider: `1.234_567_f32`
 
 error: long literal lacking separators
--> $DIR/unreadable_literal.rs:9:19
-  |
-9 |     let bad_sci = 1.123456e1;
-  |                   ^^^^^^^^^^ help: consider: `1.123_456e1`
 --> $DIR/unreadable_literal.rs:19:19
+   |
+LL |     let bad_sci = 1.123456e1;
+   |                   ^^^^^^^^^^ help: consider: `1.123_456e1`
 
-error: aborting due to 5 previous errors
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:21:17
+   |
+LL |     let fail9 = 0xabcdef;
+   |                 ^^^^^^^^ help: consider: `0x00ab_cdef`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:22:23
+   |
+LL |     let fail10: u32 = 0xBAFEBAFE;
+   |                       ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:23:18
+   |
+LL |     let fail11 = 0xabcdeff;
+   |                  ^^^^^^^^^ help: consider: `0x0abc_deff`
+
+error: long literal lacking separators
+  --> $DIR/unreadable_literal.rs:24:24
+   |
+LL |     let fail12: i128 = 0xabcabcabcabcabcabc;
+   |                        ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
+
+error: aborting due to 9 previous errors
 
index 29f34d31a8e98731081d9feed861c0aa1fdd13b0..a1f616733bd920a277f43afb1e9ce8bdfd865cc3 100644 (file)
@@ -1,19 +1,17 @@
-
-
 #![allow(unused_imports)]
 #![allow(dead_code)]
-#![warn(unsafe_removed_from_name)]
+#![warn(clippy::unsafe_removed_from_name)]
 
-use std::cell::{UnsafeCell as TotallySafeCell};
+use std::cell::UnsafeCell as TotallySafeCell;
 
 use std::cell::UnsafeCell as TotallySafeCellAgain;
 
 // Shouldn't error
-use std::cell::{UnsafeCell as SuperDangerousUnsafeCell};
-use std::cell::{UnsafeCell as Dangerunsafe};
-use std::cell::UnsafeCell as Bombsawayunsafe;
-use std::cell::{RefCell as ProbablyNotUnsafe};
+use std::cell::RefCell as ProbablyNotUnsafe;
 use std::cell::RefCell as RefCellThatCantBeUnsafe;
+use std::cell::UnsafeCell as SuperDangerousUnsafeCell;
+use std::cell::UnsafeCell as Dangerunsafe;
+use std::cell::UnsafeCell as Bombsawayunsafe;
 
 mod mod_with_some_unsafe_things {
     pub struct Safe {}
index 93f2ddd533fea547b3df4dad229cab21401a8524..1b1c62430b2556540a263082fb2a3c8f8409efec 100644 (file)
@@ -1,21 +1,21 @@
 error: removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCell`
--> $DIR/unsafe_removed_from_name.rs:7:1
-  |
-7 | use std::cell::{UnsafeCell as TotallySafeCell};
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D unsafe-removed-from-name` implied by `-D warnings`
 --> $DIR/unsafe_removed_from_name.rs:5:1
+   |
+LL | use std::cell::UnsafeCell as TotallySafeCell;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unsafe-removed-from-name` implied by `-D warnings`
 
 error: removed "unsafe" from the name of `UnsafeCell` in use as `TotallySafeCellAgain`
--> $DIR/unsafe_removed_from_name.rs:9:1
-  |
-9 | use std::cell::UnsafeCell as TotallySafeCellAgain;
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 --> $DIR/unsafe_removed_from_name.rs:7:1
+   |
+LL | use std::cell::UnsafeCell as TotallySafeCellAgain;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: removed "unsafe" from the name of `Unsafe` in use as `LieAboutModSafety`
-  --> $DIR/unsafe_removed_from_name.rs:23:1
+  --> $DIR/unsafe_removed_from_name.rs:21:1
    |
-23 | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
+LL | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
index ea72c1b1b70418b2a4997219c8b53f48421bfb37..c8a38f9fe57a17d792d40af94746005ca0cac1ac 100644 (file)
@@ -1,12 +1,8 @@
-
-
-
 #![allow(dead_code)]
-#![warn(unused_io_amount)]
+#![warn(clippy::unused_io_amount)]
 
 use std::io;
 
-// FIXME: compiletest doesn't understand errors from macro invocation span
 fn try_macro<T: io::Read + io::Write>(s: &mut T) -> io::Result<()> {
     try!(s.write(b"test"));
     let mut buf = [0u8; 4];
@@ -27,5 +23,4 @@ fn unwrap<T: io::Read + io::Write>(s: &mut T) {
     s.read(&mut buf).unwrap();
 }
 
-fn main() {
-}
+fn main() {}
index 5114d375fffeb136fb8a039af64119e163d06657..2d00338193c49c1f5a490bd4296614d7a58283fa 100644 (file)
@@ -1,42 +1,42 @@
 error: handle written amount returned or use `Write::write_all` instead
-  --> $DIR/unused_io_amount.rs:11:5
+  --> $DIR/unused_io_amount.rs:7:5
    |
-11 |     try!(s.write(b"test"));
+LL |     try!(s.write(b"test"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D unused-io-amount` implied by `-D warnings`
+   = note: `-D clippy::unused-io-amount` implied by `-D warnings`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: handle read amount returned or use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:13:5
+  --> $DIR/unused_io_amount.rs:9:5
    |
-13 |     try!(s.read(&mut buf));
+LL |     try!(s.read(&mut buf));
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
 error: handle written amount returned or use `Write::write_all` instead
-  --> $DIR/unused_io_amount.rs:18:5
+  --> $DIR/unused_io_amount.rs:14:5
    |
-18 |     s.write(b"test")?;
+LL |     s.write(b"test")?;
    |     ^^^^^^^^^^^^^^^^^
 
 error: handle read amount returned or use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:20:5
+  --> $DIR/unused_io_amount.rs:16:5
    |
-20 |     s.read(&mut buf)?;
+LL |     s.read(&mut buf)?;
    |     ^^^^^^^^^^^^^^^^^
 
 error: handle written amount returned or use `Write::write_all` instead
-  --> $DIR/unused_io_amount.rs:25:5
+  --> $DIR/unused_io_amount.rs:21:5
    |
-25 |     s.write(b"test").unwrap();
+LL |     s.write(b"test").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: handle read amount returned or use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:27:5
+  --> $DIR/unused_io_amount.rs:23:5
    |
-27 |     s.read(&mut buf).unwrap();
+LL |     s.read(&mut buf).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
index 115121dc2757a8f29362199cc6682cdf4874f90a..ae963ad6969f5bd43b0e2d698415712532cf8bbb 100644 (file)
@@ -1,12 +1,11 @@
-
-
-
-#![allow(dead_code, items_after_statements, never_loop)]
-#![warn(unused_label)]
+#![allow(dead_code, clippy::items_after_statements, clippy::never_loop)]
+#![warn(clippy::unused_label)]
 
 fn unused_label() {
     'label: for i in 1..2 {
-        if i > 4 { continue }
+        if i > 4 {
+            continue;
+        }
     }
 }
 
@@ -16,9 +15,10 @@ fn foo() {
     }
 }
 
-
 fn bla() {
-    'a: loop { break }
+    'a: loop {
+        break;
+    }
     fn blub() {}
 }
 
index 19c91e2a6a3cae6f406352a64ba37bfb56cbf5fc..d2ca0f1b57f0ee153f666335a0e0ce2d86560682 100644 (file)
@@ -1,25 +1,29 @@
 error: unused label `'label`
-  --> $DIR/unused_labels.rs:8:5
+  --> $DIR/unused_labels.rs:5:5
    |
-8  | /     'label: for i in 1..2 {
-9  | |         if i > 4 { continue }
-10 | |     }
+LL | /     'label: for i in 1..2 {
+LL | |         if i > 4 {
+LL | |             continue;
+LL | |         }
+LL | |     }
    | |_____^
    |
-   = note: `-D unused-label` implied by `-D warnings`
+   = note: `-D clippy::unused-label` implied by `-D warnings`
 
 error: unused label `'a`
-  --> $DIR/unused_labels.rs:21:5
+  --> $DIR/unused_labels.rs:19:5
    |
-21 |     'a: loop { break }
-   |     ^^^^^^^^^^^^^^^^^^
+LL | /     'a: loop {
+LL | |         break;
+LL | |     }
+   | |_____^
 
 error: unused label `'same_label_in_two_fns`
   --> $DIR/unused_labels.rs:32:5
    |
-32 | /     'same_label_in_two_fns: loop {
-33 | |         let _ = 1;
-34 | |     }
+LL | /     'same_label_in_two_fns: loop {
+LL | |         let _ = 1;
+LL | |     }
    | |_____^
 
 error: aborting due to 3 previous errors
index 8b166a34d299fc239e02f9c9c15250192ee538e2..ba7c42b3a90d4d80b8804e73efd0aa8263e46ee3 100644 (file)
@@ -1,21 +1,17 @@
+#![allow(
+    unused,
+    dead_code,
+    clippy::needless_lifetimes,
+    clippy::needless_pass_by_value,
+    clippy::trivially_copy_pass_by_ref
+)]
+#![warn(clippy::extra_unused_lifetimes)]
 
+fn empty() {}
 
-#![allow(unused, dead_code, needless_lifetimes, needless_pass_by_value, trivially_copy_pass_by_ref)]
-#![warn(extra_unused_lifetimes)]
+fn used_lt<'a>(x: &'a u8) {}
 
-fn empty() {
-
-}
-
-
-fn used_lt<'a>(x: &'a u8) {
-
-}
-
-
-fn unused_lt<'a>(x: u8) {
-
-}
+fn unused_lt<'a>(x: u8) {}
 
 fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
     // 'a is useless here since it's not directly bound
@@ -29,19 +25,14 @@ fn lt_return_only<'a>() -> &'a u8 {
     panic!()
 }
 
-fn unused_lt_blergh<'a>(x: Option<Box<Send+'a>>) {
-
-}
-
+fn unused_lt_blergh<'a>(x: Option<Box<Send + 'a>>) {}
 
 trait Foo<'a> {
     fn x(&self, a: &'a u8);
 }
 
 impl<'a> Foo<'a> for u8 {
-    fn x(&self, a: &'a u8) {
-
-    }
+    fn x(&self, a: &'a u8) {}
 }
 
 struct Bar;
@@ -51,20 +42,23 @@ fn x<'a>(&self) {}
 }
 
 // test for #489 (used lifetimes in bounds)
-pub fn parse<'a, I: Iterator<Item=&'a str>>(_it: &mut I) {
+pub fn parse<'a, I: Iterator<Item = &'a str>>(_it: &mut I) {
     unimplemented!()
 }
-pub fn parse2<'a, I>(_it: &mut I) where I: Iterator<Item=&'a str>{
+pub fn parse2<'a, I>(_it: &mut I)
+where
+    I: Iterator<Item = &'a str>,
+{
     unimplemented!()
 }
 
-struct X { x: u32 }
+struct X {
+    x: u32,
+}
 
 impl X {
     fn self_ref_with_lifetime<'a>(&'a self) {}
     fn explicit_self_with_lifetime<'a>(self: &'a Self) {}
 }
 
-fn main() {
-
-}
+fn main() {}
index f01dfda70137dbbf297746fe09b97c5d63975b5f..bf4aedd52a97364462524bd80dcc7cfc11a8010d 100644 (file)
@@ -1,21 +1,21 @@
 error: this lifetime isn't used in the function definition
-  --> $DIR/unused_lt.rs:16:14
+  --> $DIR/unused_lt.rs:14:14
    |
-16 | fn unused_lt<'a>(x: u8) {
+LL | fn unused_lt<'a>(x: u8) {}
    |              ^^
    |
-   = note: `-D extra-unused-lifetimes` implied by `-D warnings`
+   = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings`
 
 error: this lifetime isn't used in the function definition
-  --> $DIR/unused_lt.rs:20:25
+  --> $DIR/unused_lt.rs:16:25
    |
-20 | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
+LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) {
    |                         ^^
 
 error: this lifetime isn't used in the function definition
-  --> $DIR/unused_lt.rs:50:10
+  --> $DIR/unused_lt.rs:41:10
    |
-50 |     fn x<'a>(&self) {}
+LL |     fn x<'a>(&self) {}
    |          ^^
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed
new file mode 100644 (file)
index 0000000..6412458
--- /dev/null
@@ -0,0 +1,44 @@
+// run-rustfix
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+
+struct Unitter;
+impl Unitter {
+    // try to disorient the lint with multiple unit returns and newlines
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) 
+    where G: Fn() -> () {
+        let _y: &Fn() -> () = &f;
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self)  {
+        
+    }
+}
+
+fn return_unit()  {  }
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break;
+    }
+    return;
+}
diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs
new file mode 100644 (file)
index 0000000..8e31385
--- /dev/null
@@ -0,0 +1,45 @@
+// run-rustfix
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+#![deny(clippy::unused_unit)]
+
+struct Unitter;
+impl Unitter {
+    // try to disorient the lint with multiple unit returns and newlines
+    #[allow(clippy::no_effect)]
+    pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) ->
+        ()
+    where G: Fn() -> () {
+        let _y: &Fn() -> () = &f;
+        (); // this should not lint, as it's not in return type position
+    }
+}
+
+impl Into<()> for Unitter {
+    #[rustfmt::skip]
+    fn into(self) -> () {
+        ()
+    }
+}
+
+fn return_unit() -> () { () }
+
+#[allow(clippy::needless_return)]
+#[allow(clippy::never_loop)]
+fn main() {
+    let u = Unitter;
+    assert_eq!(u.get_unit(|| {}, return_unit), u.into());
+    return_unit();
+    loop {
+        break();
+    }
+    return();
+}
diff --git a/tests/ui/unused_unit.stderr b/tests/ui/unused_unit.stderr
new file mode 100644 (file)
index 0000000..c33a220
--- /dev/null
@@ -0,0 +1,52 @@
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:18:59
+   |
+LL |       pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) ->
+   |  ___________________________________________________________^
+LL | |         ()
+   | |__________^ help: remove the `-> ()`
+   |
+note: lint level defined here
+  --> $DIR/unused_unit.rs:12:9
+   |
+LL | #![deny(clippy::unused_unit)]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:28:19
+   |
+LL |     fn into(self) -> () {
+   |                   ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit expression
+  --> $DIR/unused_unit.rs:29:9
+   |
+LL |         ()
+   |         ^^ help: remove the final `()`
+
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:33:18
+   |
+LL | fn return_unit() -> () { () }
+   |                  ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit expression
+  --> $DIR/unused_unit.rs:33:26
+   |
+LL | fn return_unit() -> () { () }
+   |                          ^^ help: remove the final `()`
+
+error: unneeded `()`
+  --> $DIR/unused_unit.rs:42:14
+   |
+LL |         break();
+   |              ^^ help: remove the `()`
+
+error: unneeded `()`
+  --> $DIR/unused_unit.rs:44:11
+   |
+LL |     return();
+   |           ^^ help: remove the `()`
+
+error: aborting due to 7 previous errors
+
index 79e3900fef0e323d122787dbd089e796b88bf5c7..bfb41e4394731e03969834ae9815017d6a91fcd2 100644 (file)
@@ -1,11 +1,9 @@
-#![warn(clippy)]
+#![warn(clippy::all)]
 
 fn main() {
     let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
 }
 
 fn new_lines() {
-    let s = Some(String::from("test string"))
-        .unwrap_or("Fail".to_string())
-        .len();
+    let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
 }
index e4704dd0e43787e33e3f68a53e291f101d98b99a..c3a7464fd470ea147c52f90cd9c242dc9557ec97 100644 (file)
@@ -1,16 +1,16 @@
 error: use of `unwrap_or` followed by a function call
- --> $DIR/unwrap_or.rs:4:47
-  |
-4 |     let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
-  |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
-  |
-  = note: `-D or-fun-call` implied by `-D warnings`
 --> $DIR/unwrap_or.rs:4:47
+   |
+LL |     let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
+   |
+   = note: `-D clippy::or-fun-call` implied by `-D warnings`
 
 error: use of `unwrap_or` followed by a function call
- --> $DIR/unwrap_or.rs:9:10
-  |
-9 |         .unwrap_or("Fail".to_string())
-  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
+  --> $DIR/unwrap_or.rs:8:47
+   |
+LL |     let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len();
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())`
 
 error: aborting due to 2 previous errors
 
index acc38f15fbdc51779a20832bd599c376614c2f79..f438d442ca1a202acd158666cf4db736c2da0853 100755 (executable)
@@ -1,14 +1,4 @@
 #!/bin/bash
-#
-# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
 
 # A script to update the references for all tests. The idea is that
 # you do a run, which will generate files in the build directory
index aa99d35f7aa779924dd17c96675ee50449f3343f..cd8b3fb33c755049ddb5e31e74cb67729fdc1672 100755 (executable)
@@ -1,14 +1,4 @@
 #!/bin/bash
-#
-# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
 
 # A script to update the references for particular tests. The idea is
 # that you do a run, which will generate files in the build directory
@@ -16,7 +6,7 @@
 # script will then copy that output and replace the "expected output"
 # files. You can then commit the changes.
 #
-# If you find yourself manually editing a foo.stderr file, you're
+# If you find yourself manually editing a `foo.stderr` file, you're
 # doing it wrong.
 
 if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then
@@ -34,6 +24,7 @@ shift
 while [[ "$1" != "" ]]; do
     STDERR_NAME="${1/%.rs/.stderr}"
     STDOUT_NAME="${1/%.rs/.stdout}"
+    FIXED_NAME="${1/%.rs/.fixed}"
     shift
     if [ -f $BUILD_DIR/$STDOUT_NAME ] && \
            ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then
@@ -45,6 +36,11 @@ while [[ "$1" != "" ]]; do
         echo updating $MYDIR/$STDERR_NAME
         cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME
     fi
+    if [ -f $BUILD_DIR/$FIXED_NAME ] && \
+           ! (diff $BUILD_DIR/$FIXED_NAME $MYDIR/$FIXED_NAME >& /dev/null); then
+        echo updating $MYDIR/$FIXED_NAME
+        cp $BUILD_DIR/$FIXED_NAME $MYDIR/$FIXED_NAME
+    fi
 done
 
 
diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed
new file mode 100644 (file)
index 0000000..68af850
--- /dev/null
@@ -0,0 +1,310 @@
+// run-rustfix
+
+#![warn(clippy::use_self)]
+#![allow(dead_code)]
+#![allow(clippy::should_implement_trait)]
+
+fn main() {}
+
+mod use_self {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Self {
+            Self {}
+        }
+        fn test() -> Self {
+            Self::new()
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+}
+
+mod better {
+    struct Foo {}
+
+    impl Foo {
+        fn new() -> Self {
+            Self {}
+        }
+        fn test() -> Self {
+            Self::new()
+        }
+    }
+
+    impl Default for Foo {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+}
+
+mod lifetimes {
+    struct Foo<'a> {
+        foo_str: &'a str,
+    }
+
+    impl<'a> Foo<'a> {
+        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
+        // Foo<'b>`
+        fn foo(s: &str) -> Foo {
+            Foo { foo_str: s }
+        }
+        // cannot replace with `Self`, because that's `Foo<'a>`
+        fn bar() -> Foo<'static> {
+            Foo { foo_str: "foo" }
+        }
+
+        // FIXME: the lint does not handle lifetimed struct
+        // `Self` should be applicable here
+        fn clone(&self) -> Foo<'a> {
+            Foo { foo_str: self.foo_str }
+        }
+    }
+}
+
+#[allow(clippy::boxed_local)]
+mod traits {
+
+    use std::ops::Mul;
+
+    trait SelfTrait {
+        fn refs(p1: &Self) -> &Self;
+        fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self;
+        fn mut_refs(p1: &mut Self) -> &mut Self;
+        fn nested(p1: Box<Self>, p2: (&u8, &Self));
+        fn vals(r: Self) -> Self;
+    }
+
+    #[derive(Default)]
+    struct Bad;
+
+    impl SelfTrait for Bad {
+        fn refs(p1: &Self) -> &Self {
+            p1
+        }
+
+        fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+            p1
+        }
+
+        fn mut_refs(p1: &mut Self) -> &mut Self {
+            p1
+        }
+
+        fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
+
+        fn vals(_: Self) -> Self {
+            Self::default()
+        }
+    }
+
+    impl Mul for Bad {
+        type Output = Self;
+
+        fn mul(self, rhs: Self) -> Self {
+            rhs
+        }
+    }
+
+    #[derive(Default)]
+    struct Good;
+
+    impl SelfTrait for Good {
+        fn refs(p1: &Self) -> &Self {
+            p1
+        }
+
+        fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+            p1
+        }
+
+        fn mut_refs(p1: &mut Self) -> &mut Self {
+            p1
+        }
+
+        fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
+
+        fn vals(_: Self) -> Self {
+            Self::default()
+        }
+    }
+
+    impl Mul for Good {
+        type Output = Self;
+
+        fn mul(self, rhs: Self) -> Self {
+            rhs
+        }
+    }
+
+    trait NameTrait {
+        fn refs(p1: &u8) -> &u8;
+        fn ref_refs<'a>(p1: &'a &'a u8) -> &'a &'a u8;
+        fn mut_refs(p1: &mut u8) -> &mut u8;
+        fn nested(p1: Box<u8>, p2: (&u8, &u8));
+        fn vals(p1: u8) -> u8;
+    }
+
+    // Using `Self` instead of the type name is OK
+    impl NameTrait for u8 {
+        fn refs(p1: &Self) -> &Self {
+            p1
+        }
+
+        fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self {
+            p1
+        }
+
+        fn mut_refs(p1: &mut Self) -> &mut Self {
+            p1
+        }
+
+        fn nested(_p1: Box<Self>, _p2: (&Self, &Self)) {}
+
+        fn vals(_: Self) -> Self {
+            Self::default()
+        }
+    }
+
+    // Check that self arg isn't linted
+    impl Clone for Good {
+        fn clone(&self) -> Self {
+            // Note: Not linted and it wouldn't be valid
+            // because "can't use `Self` as a constructor`"
+            Good
+        }
+    }
+}
+
+mod issue2894 {
+    trait IntoBytes {
+        fn into_bytes(&self) -> Vec<u8>;
+    }
+
+    // This should not be linted
+    impl IntoBytes for u8 {
+        fn into_bytes(&self) -> Vec<u8> {
+            vec![*self]
+        }
+    }
+}
+
+mod existential {
+    struct Foo;
+
+    impl Foo {
+        fn bad(foos: &[Self]) -> impl Iterator<Item = &Self> {
+            foos.iter()
+        }
+
+        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
+            foos.iter()
+        }
+    }
+}
+
+mod tuple_structs {
+    pub struct TS(i32);
+
+    impl TS {
+        pub fn ts() -> Self {
+            Self(0)
+        }
+    }
+}
+
+mod macros {
+    macro_rules! use_self_expand {
+        () => {
+            fn new() -> Self {
+                Self {}
+            }
+        };
+    }
+
+    struct Foo {}
+
+    impl Foo {
+        use_self_expand!(); // Should lint in local macros
+    }
+}
+
+mod nesting {
+    struct Foo {}
+    impl Foo {
+        fn foo() {
+            #[allow(unused_imports)]
+            use self::Foo; // Can't use Self here
+            struct Bar {
+                foo: Foo, // Foo != Self
+            }
+
+            impl Bar {
+                fn bar() -> Self {
+                    Self { foo: Foo {} }
+                }
+            }
+
+            // Can't use Self here
+            fn baz() -> Foo {
+                Foo {}
+            }
+        }
+
+        // Should lint here
+        fn baz() -> Self {
+            Self {}
+        }
+    }
+
+    enum Enum {
+        A,
+    }
+    impl Enum {
+        fn method() {
+            #[allow(unused_imports)]
+            use self::Enum::*; // Issue 3425
+            static STATIC: Enum = Enum::A; // Can't use Self as type
+        }
+    }
+}
+
+mod issue3410 {
+
+    struct A;
+    struct B;
+
+    trait Trait<T> {
+        fn a(v: T);
+    }
+
+    impl Trait<Vec<A>> for Vec<B> {
+        fn a(_: Vec<A>) {}
+    }
+}
+
+#[allow(clippy::no_effect, path_statements)]
+mod rustfix {
+    mod nested {
+        pub struct A {}
+    }
+
+    impl nested::A {
+        const A: bool = true;
+
+        fn fun_1() {}
+
+        fn fun_2() {
+            Self::fun_1();
+            Self::A;
+
+            Self {};
+        }
+    }
+}
index 689c9d68d1208aa7504f6f985f32ad4a7f0bc074..7a6d415528ad569b4241ef37d52b2310c6bee0b7 100644 (file)
@@ -1,6 +1,8 @@
-#![warn(use_self)]
+// run-rustfix
+
+#![warn(clippy::use_self)]
 #![allow(dead_code)]
-#![allow(should_implement_trait)]
+#![allow(clippy::should_implement_trait)]
 
 fn main() {}
 
@@ -42,29 +44,31 @@ fn default() -> Self {
     }
 }
 
-//todo the lint does not handle lifetimed struct
-//the following module should trigger the lint on the third method only
 mod lifetimes {
-    struct Foo<'a>{foo_str: &'a str}
+    struct Foo<'a> {
+        foo_str: &'a str,
+    }
 
     impl<'a> Foo<'a> {
-        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) -> Foo<'b>`
+        // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
+        // Foo<'b>`
         fn foo(s: &str) -> Foo {
             Foo { foo_str: s }
         }
         // cannot replace with `Self`, because that's `Foo<'a>`
         fn bar() -> Foo<'static> {
-            Foo { foo_str: "foo"}
+            Foo { foo_str: "foo" }
         }
 
-        // `Self` is applicable here
+        // FIXME: the lint does not handle lifetimed struct
+        // `Self` should be applicable here
         fn clone(&self) -> Foo<'a> {
-            Foo {foo_str: self.foo_str}
+            Foo { foo_str: self.foo_str }
         }
     }
 }
 
-#[allow(boxed_local)]
+#[allow(clippy::boxed_local)]
 mod traits {
 
     use std::ops::Mul;
@@ -93,8 +97,7 @@ fn mut_refs(p1: &mut Bad) -> &mut Bad {
             p1
         }
 
-        fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {
-        }
+        fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
 
         fn vals(_: Bad) -> Bad {
             Bad::default()
@@ -125,8 +128,7 @@ fn mut_refs(p1: &mut Self) -> &mut Self {
             p1
         }
 
-        fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {
-        }
+        fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
         fn vals(_: Self) -> Self {
             Self::default()
@@ -163,8 +165,7 @@ fn mut_refs(p1: &mut Self) -> &mut Self {
             p1
         }
 
-        fn nested(_p1: Box<Self>, _p2: (&Self, &Self)) {
-        }
+        fn nested(_p1: Box<Self>, _p2: (&Self, &Self)) {}
 
         fn vals(_: Self) -> Self {
             Self::default()
@@ -193,3 +194,117 @@ fn into_bytes(&self) -> Vec<u8> {
         }
     }
 }
+
+mod existential {
+    struct Foo;
+
+    impl Foo {
+        fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
+            foos.iter()
+        }
+
+        fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
+            foos.iter()
+        }
+    }
+}
+
+mod tuple_structs {
+    pub struct TS(i32);
+
+    impl TS {
+        pub fn ts() -> Self {
+            TS(0)
+        }
+    }
+}
+
+mod macros {
+    macro_rules! use_self_expand {
+        () => {
+            fn new() -> Foo {
+                Foo {}
+            }
+        };
+    }
+
+    struct Foo {}
+
+    impl Foo {
+        use_self_expand!(); // Should lint in local macros
+    }
+}
+
+mod nesting {
+    struct Foo {}
+    impl Foo {
+        fn foo() {
+            #[allow(unused_imports)]
+            use self::Foo; // Can't use Self here
+            struct Bar {
+                foo: Foo, // Foo != Self
+            }
+
+            impl Bar {
+                fn bar() -> Bar {
+                    Bar { foo: Foo {} }
+                }
+            }
+
+            // Can't use Self here
+            fn baz() -> Foo {
+                Foo {}
+            }
+        }
+
+        // Should lint here
+        fn baz() -> Foo {
+            Foo {}
+        }
+    }
+
+    enum Enum {
+        A,
+    }
+    impl Enum {
+        fn method() {
+            #[allow(unused_imports)]
+            use self::Enum::*; // Issue 3425
+            static STATIC: Enum = Enum::A; // Can't use Self as type
+        }
+    }
+}
+
+mod issue3410 {
+
+    struct A;
+    struct B;
+
+    trait Trait<T> {
+        fn a(v: T);
+    }
+
+    impl Trait<Vec<A>> for Vec<B> {
+        fn a(_: Vec<A>) {}
+    }
+}
+
+#[allow(clippy::no_effect, path_statements)]
+mod rustfix {
+    mod nested {
+        pub struct A {}
+    }
+
+    impl nested::A {
+        const A: bool = true;
+
+        fn fun_1() {}
+
+        fn fun_2() {
+            nested::A::fun_1();
+            nested::A::A;
+
+            nested::A {};
+        }
+    }
+}
index 899361012524f94e5550ad082c2ab033276b6c08..bf1f41fd64ede87bd15c2e69e6b085e52ff66f03 100644 (file)
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:11:21
+  --> $DIR/use_self.rs:13:21
    |
-11 |         fn new() -> Foo {
+LL |         fn new() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
    |
-   = note: `-D use-self` implied by `-D warnings`
+   = note: `-D clippy::use-self` implied by `-D warnings`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:12:13
+  --> $DIR/use_self.rs:14:13
    |
-12 |             Foo {}
+LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:14:22
+  --> $DIR/use_self.rs:16:22
    |
-14 |         fn test() -> Foo {
+LL |         fn test() -> Foo {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:15:13
+  --> $DIR/use_self.rs:17:13
    |
-15 |             Foo::new()
-   |             ^^^^^^^^ help: use the applicable keyword: `Self`
+LL |             Foo::new()
+   |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:20:25
+  --> $DIR/use_self.rs:22:25
    |
-20 |         fn default() -> Foo {
+LL |         fn default() -> Foo {
    |                         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:21:13
+  --> $DIR/use_self.rs:23:13
    |
-21 |             Foo::new()
-   |             ^^^^^^^^ help: use the applicable keyword: `Self`
+LL |             Foo::new()
+   |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:84:22
+  --> $DIR/use_self.rs:88:22
    |
-84 |         fn refs(p1: &Bad) -> &Bad {
+LL |         fn refs(p1: &Bad) -> &Bad {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:84:31
+  --> $DIR/use_self.rs:88:31
    |
-84 |         fn refs(p1: &Bad) -> &Bad {
+LL |         fn refs(p1: &Bad) -> &Bad {
    |                               ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:88:37
+  --> $DIR/use_self.rs:92:37
    |
-88 |         fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
+LL |         fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
    |                                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:88:53
+  --> $DIR/use_self.rs:92:53
    |
-88 |         fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
+LL |         fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
    |                                                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:92:30
+  --> $DIR/use_self.rs:96:30
    |
-92 |         fn mut_refs(p1: &mut Bad) -> &mut Bad {
+LL |         fn mut_refs(p1: &mut Bad) -> &mut Bad {
    |                              ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:92:43
+  --> $DIR/use_self.rs:96:43
    |
-92 |         fn mut_refs(p1: &mut Bad) -> &mut Bad {
+LL |         fn mut_refs(p1: &mut Bad) -> &mut Bad {
    |                                           ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:96:28
+  --> $DIR/use_self.rs:100:28
    |
-96 |         fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {
+LL |         fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
    |                            ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:96:46
+  --> $DIR/use_self.rs:100:46
    |
-96 |         fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {
+LL |         fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
    |                                              ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:99:20
+  --> $DIR/use_self.rs:102:20
    |
-99 |         fn vals(_: Bad) -> Bad {
+LL |         fn vals(_: Bad) -> Bad {
    |                    ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:99:28
+  --> $DIR/use_self.rs:102:28
    |
-99 |         fn vals(_: Bad) -> Bad {
+LL |         fn vals(_: Bad) -> Bad {
    |                            ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:100:13
-    |
-100 |             Bad::default()
-    |             ^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+  --> $DIR/use_self.rs:103:13
+   |
+LL |             Bad::default()
+   |             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:108:23
+   |
+LL |         type Output = Bad;
+   |                       ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:110:27
+   |
+LL |         fn mul(self, rhs: Bad) -> Bad {
+   |                           ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:110:35
+   |
+LL |         fn mul(self, rhs: Bad) -> Bad {
+   |                                   ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:202:56
+   |
+LL |         fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
+   |                                                        ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:217:13
+   |
+LL |             TS(0)
+   |             ^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:225:25
+   |
+LL |             fn new() -> Foo {
+   |                         ^^^ help: use the applicable keyword: `Self`
+...
+LL |         use_self_expand!(); // Should lint in local macros
+   |         ------------------- in this macro invocation
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:226:17
+   |
+LL |                 Foo {}
+   |                 ^^^ help: use the applicable keyword: `Self`
+...
+LL |         use_self_expand!(); // Should lint in local macros
+   |         ------------------- in this macro invocation
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:261:21
+   |
+LL |         fn baz() -> Foo {
+   |                     ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:262:13
+   |
+LL |             Foo {}
+   |             ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:249:29
+   |
+LL |                 fn bar() -> Bar {
+   |                             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:105:23
-    |
-105 |         type Output = Bad;
-    |                       ^^^ help: use the applicable keyword: `Self`
+  --> $DIR/use_self.rs:250:21
+   |
+LL |                     Bar { foo: Foo {} }
+   |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:107:27
-    |
-107 |         fn mul(self, rhs: Bad) -> Bad {
-    |                           ^^^ help: use the applicable keyword: `Self`
+  --> $DIR/use_self.rs:304:13
+   |
+LL |             nested::A::fun_1();
+   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-   --> $DIR/use_self.rs:107:35
-    |
-107 |         fn mul(self, rhs: Bad) -> Bad {
-    |                                   ^^^ help: use the applicable keyword: `Self`
+  --> $DIR/use_self.rs:305:13
+   |
+LL |             nested::A::A;
+   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:307:13
+   |
+LL |             nested::A {};
+   |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
-error: aborting due to 20 previous errors
+error: aborting due to 31 previous errors
 
index 60a2c4e8b4c9a70458795046452cbdc56159ea57..5a02ff5d193de27d073f7a7bfd428240f48c5e27 100644 (file)
@@ -1,24 +1,31 @@
+// aux-build:proc_macro_derive.rs
 
+#![warn(clippy::all)]
+#![allow(clippy::blacklisted_name)]
+#![warn(clippy::used_underscore_binding)]
 
-#![warn(clippy)]
+#[macro_use]
+extern crate proc_macro_derive;
 
-#![allow(blacklisted_name)]
-#![warn(used_underscore_binding)]
+// This should not trigger the lint. There's underscore binding inside the external derive that
+// would trigger the `used_underscore_binding` lint.
+#[derive(DeriveSomething)]
+struct Baz;
 
 macro_rules! test_macro {
     () => {{
         let _foo = 42;
         _foo + 1
-    }}
+    }};
 }
 
-/// Test that we lint if we use a binding with a single leading underscore
+/// Tests that we lint if we use a binding with a single leading underscore
 fn prefix_underscore(_foo: u32) -> u32 {
     _foo + 1
 }
 
-/// Test that we lint if we use a `_`-variable defined outside within a macro expansion
-fn in_macro(_foo: u32) {
+/// Tests that we lint if we use a `_`-variable defined outside within a macro expansion
+fn in_macro_or_desugar(_foo: u32) {
     println!("{}", _foo);
     assert_eq!(_foo, _foo);
 
@@ -30,23 +37,23 @@ struct StructFieldTest {
     _underscore_field: u32,
 }
 
-/// Test that we lint the use of a struct field which is prefixed with an underscore
+/// Tests that we lint the use of a struct field which is prefixed with an underscore
 fn in_struct_field() {
     let mut s = StructFieldTest { _underscore_field: 0 };
     s._underscore_field += 1;
 }
 
-/// Test that we do not lint if the underscore is not a prefix
+/// Tests that we do not lint if the underscore is not a prefix
 fn non_prefix_underscore(some_foo: u32) -> u32 {
     some_foo + 1
 }
 
-/// Test that we do not lint if we do not use the binding (simple case)
+/// Tests that we do not lint if we do not use the binding (simple case)
 fn unused_underscore_simple(_foo: u32) -> u32 {
     1
 }
 
-/// Test that we do not lint if we do not use the binding (complex case). This checks for
+/// Tests that we do not lint if we do not use the binding (complex case). This checks for
 /// compatibility with the built-in `unused_variables` lint.
 fn unused_underscore_complex(mut _foo: u32) -> u32 {
     _foo += 1;
@@ -54,7 +61,7 @@ fn unused_underscore_complex(mut _foo: u32) -> u32 {
     1
 }
 
-///Test that we do not lint for multiple underscores
+/// Test that we do not lint for multiple underscores
 fn multiple_underscores(__foo: u32) -> u32 {
     __foo + 1
 }
@@ -64,10 +71,10 @@ fn _fn_test() {}
 struct _StructTest;
 enum _EnumTest {
     _Empty,
-    _Value(_StructTest)
+    _Value(_StructTest),
 }
 
-/// Test that we do not lint for non-variable bindings
+/// Tests that we do not lint for non-variable bindings
 fn non_variables() {
     _fn_test();
     let _s = _StructTest;
@@ -83,7 +90,7 @@ fn main() {
     let foo = 0u32;
     // tests of unused_underscore lint
     let _ = prefix_underscore(foo);
-    in_macro(foo);
+    in_macro_or_desugar(foo);
     in_struct_field();
     // possible false positives
     let _ = non_prefix_underscore(foo);
index 712f81c1b6ff8d4f17e33875c372c9ed8f447ea6..8216a3c66e5bed10a2adc159aa264cb58d669ddb 100644 (file)
@@ -1,33 +1,33 @@
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
-  --> $DIR/used_underscore_binding.rs:17:5
+  --> $DIR/used_underscore_binding.rs:24:5
    |
-17 |     _foo + 1
+LL |     _foo + 1
    |     ^^^^
    |
-   = note: `-D used-underscore-binding` implied by `-D warnings`
+   = note: `-D clippy::used-underscore-binding` implied by `-D warnings`
 
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
-  --> $DIR/used_underscore_binding.rs:22:20
+  --> $DIR/used_underscore_binding.rs:29:20
    |
-22 |     println!("{}", _foo);
+LL |     println!("{}", _foo);
    |                    ^^^^
 
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
-  --> $DIR/used_underscore_binding.rs:23:16
+  --> $DIR/used_underscore_binding.rs:30:16
    |
-23 |     assert_eq!(_foo, _foo);
+LL |     assert_eq!(_foo, _foo);
    |                ^^^^
 
 error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
-  --> $DIR/used_underscore_binding.rs:23:22
+  --> $DIR/used_underscore_binding.rs:30:22
    |
-23 |     assert_eq!(_foo, _foo);
+LL |     assert_eq!(_foo, _foo);
    |                      ^^^^
 
 error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used.
-  --> $DIR/used_underscore_binding.rs:36:5
+  --> $DIR/used_underscore_binding.rs:43:5
    |
-36 |     s._underscore_field += 1;
+LL |     s._underscore_field += 1;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/useful_asref.rs b/tests/ui/useful_asref.rs
new file mode 100644 (file)
index 0000000..a9f0170
--- /dev/null
@@ -0,0 +1,13 @@
+#![deny(clippy::useless_asref)]
+
+trait Trait {
+    fn as_ptr(&self);
+}
+
+impl<'a> Trait for &'a [u8] {
+    fn as_ptr(&self) {
+        self.as_ref().as_ptr();
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed
new file mode 100644 (file)
index 0000000..c6fce5d
--- /dev/null
@@ -0,0 +1,136 @@
+// run-rustfix
+
+#![deny(clippy::useless_asref)]
+#![allow(clippy::trivially_copy_pass_by_ref)]
+
+use std::fmt::Debug;
+
+struct FakeAsRef;
+
+#[allow(clippy::should_implement_trait)]
+impl FakeAsRef {
+    fn as_ref(&self) -> &Self {
+        self
+    }
+}
+
+struct MoreRef;
+
+impl<'a, 'b, 'c> AsRef<&'a &'b &'c MoreRef> for MoreRef {
+    fn as_ref(&self) -> &&'a &'b &'c MoreRef {
+        &&&&MoreRef
+    }
+}
+
+fn foo_rstr(x: &str) {
+    println!("{:?}", x);
+}
+fn foo_rslice(x: &[i32]) {
+    println!("{:?}", x);
+}
+fn foo_mrslice(x: &mut [i32]) {
+    println!("{:?}", x);
+}
+fn foo_rrrrmr(_: &&&&MoreRef) {
+    println!("so many refs");
+}
+
+fn not_ok() {
+    let rstr: &str = "hello";
+    let mut mrslice: &mut [i32] = &mut [1, 2, 3];
+
+    {
+        let rslice: &[i32] = &*mrslice;
+        foo_rstr(rstr);
+        foo_rstr(rstr);
+        foo_rslice(rslice);
+        foo_rslice(rslice);
+    }
+    {
+        foo_mrslice(mrslice);
+        foo_mrslice(mrslice);
+        foo_rslice(mrslice);
+        foo_rslice(mrslice);
+    }
+
+    {
+        let rrrrrstr = &&&&rstr;
+        let rrrrrslice = &&&&&*mrslice;
+        foo_rslice(rrrrrslice);
+        foo_rslice(rrrrrslice);
+        foo_rstr(rrrrrstr);
+        foo_rstr(rrrrrstr);
+    }
+    {
+        let mrrrrrslice = &mut &mut &mut &mut mrslice;
+        foo_mrslice(mrrrrrslice);
+        foo_mrslice(mrrrrrslice);
+        foo_rslice(mrrrrrslice);
+        foo_rslice(mrrrrrslice);
+    }
+    #[allow(unused_parens, clippy::double_parens)]
+    foo_rrrrmr((&&&&MoreRef));
+
+    generic_not_ok(mrslice);
+    generic_ok(mrslice);
+}
+
+fn ok() {
+    let string = "hello".to_owned();
+    let mut arr = [1, 2, 3];
+    let mut vec = vec![1, 2, 3];
+
+    {
+        foo_rstr(string.as_ref());
+        foo_rslice(arr.as_ref());
+        foo_rslice(vec.as_ref());
+    }
+    {
+        foo_mrslice(arr.as_mut());
+        foo_mrslice(vec.as_mut());
+    }
+
+    {
+        let rrrrstring = &&&&string;
+        let rrrrarr = &&&&arr;
+        let rrrrvec = &&&&vec;
+        foo_rstr(rrrrstring.as_ref());
+        foo_rslice(rrrrarr.as_ref());
+        foo_rslice(rrrrvec.as_ref());
+    }
+    {
+        let mrrrrarr = &mut &mut &mut &mut arr;
+        let mrrrrvec = &mut &mut &mut &mut vec;
+        foo_mrslice(mrrrrarr.as_mut());
+        foo_mrslice(mrrrrvec.as_mut());
+    }
+    FakeAsRef.as_ref();
+    foo_rrrrmr(MoreRef.as_ref());
+
+    generic_not_ok(arr.as_mut());
+    generic_ok(&mut arr);
+}
+
+fn foo_mrt<T: Debug + ?Sized>(t: &mut T) {
+    println!("{:?}", t);
+}
+fn foo_rt<T: Debug + ?Sized>(t: &T) {
+    println!("{:?}", t);
+}
+
+fn generic_not_ok<T: AsMut<T> + AsRef<T> + Debug + ?Sized>(mrt: &mut T) {
+    foo_mrt(mrt);
+    foo_mrt(mrt);
+    foo_rt(mrt);
+    foo_rt(mrt);
+}
+
+fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
+    foo_mrt(mru.as_mut());
+    foo_rt(mru.as_ref());
+}
+
+fn main() {
+    not_ok();
+    ok();
+}
index 7508cdc7b4336452636578ae4c047daf7633ab28..1d23760bd1480e4672633da850473c4910db243d 100644 (file)
@@ -1,12 +1,17 @@
-#![deny(useless_asref)]
-#![allow(trivially_copy_pass_by_ref)]
+// run-rustfix
+
+#![deny(clippy::useless_asref)]
+#![allow(clippy::trivially_copy_pass_by_ref)]
+
 use std::fmt::Debug;
 
 struct FakeAsRef;
 
-#[allow(should_implement_trait)]
+#[allow(clippy::should_implement_trait)]
 impl FakeAsRef {
-    fn as_ref(&self) -> &Self { self }
+    fn as_ref(&self) -> &Self {
+        self
+    }
 }
 
 struct MoreRef;
@@ -17,14 +22,22 @@ fn as_ref(&self) -> &&'a &'b &'c MoreRef {
     }
 }
 
-fn foo_rstr(x: &str) { println!("{:?}", x); }
-fn foo_rslice(x: &[i32]) { println!("{:?}", x); }
-fn foo_mrslice(x: &mut [i32]) { println!("{:?}", x); }
-fn foo_rrrrmr(_: &&&&MoreRef) { println!("so many refs"); }
+fn foo_rstr(x: &str) {
+    println!("{:?}", x);
+}
+fn foo_rslice(x: &[i32]) {
+    println!("{:?}", x);
+}
+fn foo_mrslice(x: &mut [i32]) {
+    println!("{:?}", x);
+}
+fn foo_rrrrmr(_: &&&&MoreRef) {
+    println!("so many refs");
+}
 
 fn not_ok() {
     let rstr: &str = "hello";
-    let mut mrslice: &mut [i32] = &mut [1,2,3];
+    let mut mrslice: &mut [i32] = &mut [1, 2, 3];
 
     {
         let rslice: &[i32] = &*mrslice;
@@ -55,6 +68,7 @@ fn not_ok() {
         foo_rslice(mrrrrrslice.as_ref());
         foo_rslice(mrrrrrslice);
     }
+    #[allow(unused_parens, clippy::double_parens)]
     foo_rrrrmr((&&&&MoreRef).as_ref());
 
     generic_not_ok(mrslice);
@@ -63,8 +77,8 @@ fn not_ok() {
 
 fn ok() {
     let string = "hello".to_owned();
-    let mut arr = [1,2,3];
-    let mut vec = vec![1,2,3];
+    let mut arr = [1, 2, 3];
+    let mut vec = vec![1, 2, 3];
 
     {
         foo_rstr(string.as_ref());
@@ -97,8 +111,12 @@ fn ok() {
     generic_ok(&mut arr);
 }
 
-fn foo_mrt<T: Debug + ?Sized>(t: &mut T) { println!("{:?}", t); }
-fn foo_rt<T: Debug + ?Sized>(t: &T) { println!("{:?}", t); }
+fn foo_mrt<T: Debug + ?Sized>(t: &mut T) {
+    println!("{:?}", t);
+}
+fn foo_rt<T: Debug + ?Sized>(t: &T) {
+    println!("{:?}", t);
+}
 
 fn generic_not_ok<T: AsMut<T> + AsRef<T> + Debug + ?Sized>(mrt: &mut T) {
     foo_mrt(mrt.as_mut());
index 875d830a35341a8325e6f79d27c7b20c86391794..dd0613fc767136ee04854ff9b6f47635d1e9ecb4 100644 (file)
@@ -1,74 +1,74 @@
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:31:18
+  --> $DIR/useless_asref.rs:44:18
    |
-31 |         foo_rstr(rstr.as_ref());
+LL |         foo_rstr(rstr.as_ref());
    |                  ^^^^^^^^^^^^^ help: try this: `rstr`
    |
 note: lint level defined here
-  --> $DIR/useless_asref.rs:1:9
+  --> $DIR/useless_asref.rs:3:9
    |
-1  | #![deny(useless_asref)]
-   |         ^^^^^^^^^^^^^
+LL | #![deny(clippy::useless_asref)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:33:20
+  --> $DIR/useless_asref.rs:46:20
    |
-33 |         foo_rslice(rslice.as_ref());
+LL |         foo_rslice(rslice.as_ref());
    |                    ^^^^^^^^^^^^^^^ help: try this: `rslice`
 
 error: this call to `as_mut` does nothing
-  --> $DIR/useless_asref.rs:37:21
+  --> $DIR/useless_asref.rs:50:21
    |
-37 |         foo_mrslice(mrslice.as_mut());
+LL |         foo_mrslice(mrslice.as_mut());
    |                     ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:39:20
+  --> $DIR/useless_asref.rs:52:20
    |
-39 |         foo_rslice(mrslice.as_ref());
+LL |         foo_rslice(mrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^ help: try this: `mrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:46:20
+  --> $DIR/useless_asref.rs:59:20
    |
-46 |         foo_rslice(rrrrrslice.as_ref());
+LL |         foo_rslice(rrrrrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:48:18
+  --> $DIR/useless_asref.rs:61:18
    |
-48 |         foo_rstr(rrrrrstr.as_ref());
+LL |         foo_rstr(rrrrrstr.as_ref());
    |                  ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr`
 
 error: this call to `as_mut` does nothing
-  --> $DIR/useless_asref.rs:53:21
+  --> $DIR/useless_asref.rs:66:21
    |
-53 |         foo_mrslice(mrrrrrslice.as_mut());
+LL |         foo_mrslice(mrrrrrslice.as_mut());
    |                     ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:55:20
+  --> $DIR/useless_asref.rs:68:20
    |
-55 |         foo_rslice(mrrrrrslice.as_ref());
+LL |         foo_rslice(mrrrrrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:58:16
+  --> $DIR/useless_asref.rs:72:16
    |
-58 |     foo_rrrrmr((&&&&MoreRef).as_ref());
+LL |     foo_rrrrmr((&&&&MoreRef).as_ref());
    |                ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)`
 
 error: this call to `as_mut` does nothing
-   --> $DIR/useless_asref.rs:104:13
-    |
-104 |     foo_mrt(mrt.as_mut());
-    |             ^^^^^^^^^^^^ help: try this: `mrt`
+  --> $DIR/useless_asref.rs:122:13
+   |
+LL |     foo_mrt(mrt.as_mut());
+   |             ^^^^^^^^^^^^ help: try this: `mrt`
 
 error: this call to `as_ref` does nothing
-   --> $DIR/useless_asref.rs:106:12
-    |
-106 |     foo_rt(mrt.as_ref());
-    |            ^^^^^^^^^^^^ help: try this: `mrt`
+  --> $DIR/useless_asref.rs:124:12
+   |
+LL |     foo_rt(mrt.as_ref());
+   |            ^^^^^^^^^^^^ help: try this: `mrt`
 
 error: aborting due to 11 previous errors
 
index 68c7d2007a6b65bf258cf716a1e693ef365937d2..2ef1ec7dad4682f8cdf69e741b1458ddd6904c72 100644 (file)
@@ -1,22 +1,35 @@
+// aux-build:proc_macro_derive.rs
 
+#![warn(clippy::useless_attribute)]
 
-#![warn(useless_attribute)]
-
-#[allow(dead_code, unused_extern_crates)]
-#[cfg_attr(feature = "cargo-clippy", allow(dead_code, unused_extern_crates))]
+#[allow(dead_code)]
+#[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
+#[rustfmt::skip]
 #[cfg_attr(feature = "cargo-clippy",
-           allow(dead_code, unused_extern_crates))]
+           allow(dead_code))]
 #[allow(unused_imports)]
+#[allow(unused_extern_crates)]
 #[macro_use]
 extern crate clippy_lints;
 
+#[macro_use]
+extern crate proc_macro_derive;
+
 // don't lint on unused_import for `use` items
 #[allow(unused_imports)]
 use std::collections;
 
 // don't lint on deprecated for `use` items
-mod foo { #[deprecated] pub struct Bar; }
+mod foo {
+    #[deprecated]
+    pub struct Bar;
+}
 #[allow(deprecated)]
 pub use foo::Bar;
 
+// This should not trigger the lint. There's lint level definitions inside the external derive
+// that would trigger the useless_attribute lint.
+#[derive(DeriveSomething)]
+struct Baz;
+
 fn main() {}
index 84b81e5610792e42e11f907e39999071cb1a910f..50ba3d1b01625dde703803136cb5b61b4f651b87 100644 (file)
@@ -1,16 +1,16 @@
 error: useless lint attribute
- --> $DIR/useless_attribute.rs:5:1
-  |
-5 | #[allow(dead_code, unused_extern_crates)]
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code, unused_extern_crates)]`
-  |
-  = note: `-D useless-attribute` implied by `-D warnings`
 --> $DIR/useless_attribute.rs:5:1
+   |
+LL | #[allow(dead_code)]
+   | ^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(dead_code)]`
+   |
+   = note: `-D clippy::useless-attribute` implied by `-D warnings`
 
 error: useless lint attribute
- --> $DIR/useless_attribute.rs:6:1
-  |
-6 | #[cfg_attr(feature = "cargo-clippy", allow(dead_code, unused_extern_crates))]
-  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code, unused_extern_crates))`
 --> $DIR/useless_attribute.rs:6:1
+   |
+LL | #[cfg_attr(feature = "cargo-clippy", allow(dead_code))]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(feature = "cargo-clippy", allow(dead_code)`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed
new file mode 100644 (file)
index 0000000..e73a791
--- /dev/null
@@ -0,0 +1,55 @@
+// run-rustfix
+
+#![warn(clippy::useless_vec)]
+
+#[derive(Debug)]
+struct NonCopy;
+
+fn on_slice(_: &[u8]) {}
+#[allow(clippy::ptr_arg)]
+fn on_vec(_: &Vec<u8>) {}
+
+struct Line {
+    length: usize,
+}
+
+impl Line {
+    fn length(&self) -> usize {
+        self.length
+    }
+}
+
+fn main() {
+    on_slice(&[]);
+    on_slice(&[]);
+
+    on_slice(&[1, 2]);
+    on_slice(&[1, 2]);
+
+    on_slice(&[1, 2]);
+    on_slice(&[1, 2]);
+    #[rustfmt::skip]
+    on_slice(&[1, 2]);
+    on_slice(&[1, 2]);
+
+    on_slice(&[1; 2]);
+    on_slice(&[1; 2]);
+
+    on_vec(&vec![]);
+    on_vec(&vec![1, 2]);
+    on_vec(&vec![1; 2]);
+
+    // Now with non-constant expressions
+    let line = Line { length: 2 };
+
+    on_slice(&vec![2; line.length]);
+    on_slice(&vec![2; line.length()]);
+
+    for a in &[1, 2, 3] {
+        println!("{:?}", a);
+    }
+
+    for a in vec![NonCopy, NonCopy] {
+        println!("{:?}", a);
+    }
+}
index 23e438724540a5d199696bde2a5448d91e41b24f..3eb960f53d7af7dc33dc7baa14a51b36c7f65e05 100644 (file)
@@ -1,13 +1,12 @@
+// run-rustfix
 
-
-
-#![warn(useless_vec)]
+#![warn(clippy::useless_vec)]
 
 #[derive(Debug)]
 struct NonCopy;
 
 fn on_slice(_: &[u8]) {}
-#[allow(ptr_arg)]
+#[allow(clippy::ptr_arg)]
 fn on_vec(_: &Vec<u8>) {}
 
 struct Line {
@@ -27,9 +26,9 @@ fn main() {
     on_slice(&vec![1, 2]);
     on_slice(&[1, 2]);
 
-    on_slice(&vec ![1, 2]);
+    on_slice(&vec![1, 2]);
     on_slice(&[1, 2]);
-
+    #[rustfmt::skip]
     on_slice(&vec!(1, 2));
     on_slice(&[1, 2]);
 
index 6a47eb5b064ea559bbdb6b9372762630ce6a631f..37e28ebddb55391cddcbbfccca830ffe30aff268 100644 (file)
@@ -1,39 +1,39 @@
 error: useless use of `vec!`
-  --> $DIR/vec.rs:24:14
+  --> $DIR/vec.rs:23:14
    |
-24 |     on_slice(&vec![]);
+LL |     on_slice(&vec![]);
    |              ^^^^^^^ help: you can use a slice directly: `&[]`
    |
-   = note: `-D useless-vec` implied by `-D warnings`
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:27:14
+  --> $DIR/vec.rs:26:14
    |
-27 |     on_slice(&vec![1, 2]);
+LL |     on_slice(&vec![1, 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:30:14
+  --> $DIR/vec.rs:29:14
    |
-30 |     on_slice(&vec ![1, 2]);
-   |              ^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
+LL |     on_slice(&vec![1, 2]);
+   |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:33:14
+  --> $DIR/vec.rs:32:14
    |
-33 |     on_slice(&vec!(1, 2));
+LL |     on_slice(&vec!(1, 2));
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:36:14
+  --> $DIR/vec.rs:35:14
    |
-36 |     on_slice(&vec![1; 2]);
+LL |     on_slice(&vec![1; 2]);
    |              ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]`
 
 error: useless use of `vec!`
-  --> $DIR/vec.rs:49:14
+  --> $DIR/vec.rs:48:14
    |
-49 |     for a in vec![1, 2, 3] {
+LL |     for a in vec![1, 2, 3] {
    |              ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]`
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/vec_box_sized.fixed b/tests/ui/vec_box_sized.fixed
new file mode 100644 (file)
index 0000000..a56dac8
--- /dev/null
@@ -0,0 +1,36 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct SizedStruct(i32);
+struct UnsizedStruct([i32]);
+
+/// The following should trigger the lint
+mod should_trigger {
+    use super::SizedStruct;
+
+    struct StructWithVecBox {
+        sized_type: Vec<SizedStruct>,
+    }
+
+    struct A(Vec<SizedStruct>);
+    struct B(Vec<Vec<u32>>);
+}
+
+/// The following should not trigger the lint
+mod should_not_trigger {
+    use super::UnsizedStruct;
+
+    struct C(Vec<Box<UnsizedStruct>>);
+
+    struct StructWithVecBoxButItsUnsized {
+        unsized_type: Vec<Box<UnsizedStruct>>,
+    }
+
+    struct TraitVec<T: ?Sized> {
+        // Regression test for #3720. This was causing an ICE.
+        inner: Vec<Box<T>>,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/vec_box_sized.rs b/tests/ui/vec_box_sized.rs
new file mode 100644 (file)
index 0000000..32d1e94
--- /dev/null
@@ -0,0 +1,36 @@
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct SizedStruct(i32);
+struct UnsizedStruct([i32]);
+
+/// The following should trigger the lint
+mod should_trigger {
+    use super::SizedStruct;
+
+    struct StructWithVecBox {
+        sized_type: Vec<Box<SizedStruct>>,
+    }
+
+    struct A(Vec<Box<SizedStruct>>);
+    struct B(Vec<Vec<Box<(u32)>>>);
+}
+
+/// The following should not trigger the lint
+mod should_not_trigger {
+    use super::UnsizedStruct;
+
+    struct C(Vec<Box<UnsizedStruct>>);
+
+    struct StructWithVecBoxButItsUnsized {
+        unsized_type: Vec<Box<UnsizedStruct>>,
+    }
+
+    struct TraitVec<T: ?Sized> {
+        // Regression test for #3720. This was causing an ICE.
+        inner: Vec<Box<T>>,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/vec_box_sized.stderr b/tests/ui/vec_box_sized.stderr
new file mode 100644 (file)
index 0000000..b33880b
--- /dev/null
@@ -0,0 +1,22 @@
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+  --> $DIR/vec_box_sized.rs:13:21
+   |
+LL |         sized_type: Vec<Box<SizedStruct>>,
+   |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
+   |
+   = note: `-D clippy::vec-box` implied by `-D warnings`
+
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+  --> $DIR/vec_box_sized.rs:16:14
+   |
+LL |     struct A(Vec<Box<SizedStruct>>);
+   |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec<SizedStruct>`
+
+error: `Vec<T>` is already on the heap, the boxing is unnecessary.
+  --> $DIR/vec_box_sized.rs:17:18
+   |
+LL |     struct B(Vec<Vec<Box<(u32)>>>);
+   |                  ^^^^^^^^^^^^^^^ help: try: `Vec<u32>`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/while_let_loop.rs b/tests/ui/while_let_loop.rs
new file mode 100644 (file)
index 0000000..3ce699f
--- /dev/null
@@ -0,0 +1,119 @@
+#![warn(clippy::while_let_loop)]
+
+fn main() {
+    let y = Some(true);
+    loop {
+        if let Some(_x) = y {
+            let _v = 1;
+        } else {
+            break;
+        }
+    }
+
+    #[allow(clippy::never_loop)]
+    loop {
+        // no error, break is not in else clause
+        if let Some(_x) = y {
+            let _v = 1;
+        }
+        break;
+    }
+
+    loop {
+        match y {
+            Some(_x) => true,
+            None => break,
+        };
+    }
+
+    loop {
+        let x = match y {
+            Some(x) => x,
+            None => break,
+        };
+        let _x = x;
+        let _str = "foo";
+    }
+
+    loop {
+        let x = match y {
+            Some(x) => x,
+            None => break,
+        };
+        {
+            let _a = "bar";
+        };
+        {
+            let _b = "foobar";
+        }
+    }
+
+    loop {
+        // no error, else branch does something other than break
+        match y {
+            Some(_x) => true,
+            _ => {
+                let _z = 1;
+                break;
+            },
+        };
+    }
+
+    while let Some(x) = y {
+        // no error, obviously
+        println!("{}", x);
+    }
+
+    // #675, this used to have a wrong suggestion
+    loop {
+        let (e, l) = match "".split_whitespace().next() {
+            Some(word) => (word.is_empty(), word.len()),
+            None => break,
+        };
+
+        let _ = (e, l);
+    }
+}
+
+fn issue771() {
+    let mut a = 100;
+    let b = Some(true);
+    loop {
+        if a > 10 {
+            break;
+        }
+
+        match b {
+            Some(_) => a = 0,
+            None => break,
+        }
+    }
+}
+
+fn issue1017() {
+    let r: Result<u32, u32> = Ok(42);
+    let mut len = 1337;
+
+    loop {
+        match r {
+            Err(_) => len = 0,
+            Ok(length) => {
+                len = length;
+                break;
+            },
+        }
+    }
+}
+
+#[allow(clippy::never_loop)]
+fn issue1948() {
+    // should not trigger clippy::while_let_loop lint because break passes an expression
+    let a = Some(10);
+    let b = loop {
+        if let Some(c) = a {
+            break Some(c);
+        } else {
+            break None;
+        }
+    };
+}
diff --git a/tests/ui/while_let_loop.stderr b/tests/ui/while_let_loop.stderr
new file mode 100644 (file)
index 0000000..13dd0ee
--- /dev/null
@@ -0,0 +1,63 @@
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:5:5
+   |
+LL | /     loop {
+LL | |         if let Some(_x) = y {
+LL | |             let _v = 1;
+LL | |         } else {
+LL | |             break;
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `while let Some(_x) = y { .. }`
+   |
+   = note: `-D clippy::while-let-loop` implied by `-D warnings`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:22:5
+   |
+LL | /     loop {
+LL | |         match y {
+LL | |             Some(_x) => true,
+LL | |             None => break,
+LL | |         };
+LL | |     }
+   | |_____^ help: try: `while let Some(_x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:29:5
+   |
+LL | /     loop {
+LL | |         let x = match y {
+LL | |             Some(x) => x,
+LL | |             None => break,
+...  |
+LL | |         let _str = "foo";
+LL | |     }
+   | |_____^ help: try: `while let Some(x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:38:5
+   |
+LL | /     loop {
+LL | |         let x = match y {
+LL | |             Some(x) => x,
+LL | |             None => break,
+...  |
+LL | |         }
+LL | |     }
+   | |_____^ help: try: `while let Some(x) = y { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> $DIR/while_let_loop.rs:68:5
+   |
+LL | /     loop {
+LL | |         let (e, l) = match "".split_whitespace().next() {
+LL | |             Some(word) => (word.is_empty(), word.len()),
+LL | |             None => break,
+...  |
+LL | |         let _ = (e, l);
+LL | |     }
+   | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs
new file mode 100644 (file)
index 0000000..01838ee
--- /dev/null
@@ -0,0 +1,132 @@
+#![warn(clippy::while_let_on_iterator)]
+#![allow(clippy::never_loop, clippy::cognitive_complexity)]
+
+fn main() {
+    let mut iter = 1..20;
+    while let Option::Some(x) = iter.next() {
+        println!("{}", x);
+    }
+
+    let mut iter = 1..20;
+    while let Some(x) = iter.next() {
+        println!("{}", x);
+    }
+
+    let mut iter = 1..20;
+    while let Some(_) = iter.next() {}
+
+    let mut iter = 1..20;
+    while let None = iter.next() {} // this is fine (if nonsensical)
+
+    let mut iter = 1..20;
+    if let Some(x) = iter.next() {
+        // also fine
+        println!("{}", x)
+    }
+
+    // the following shouldn't warn because it can't be written with a for loop
+    let mut iter = 1u32..20;
+    while let Some(x) = iter.next() {
+        println!("next: {:?}", iter.next())
+    }
+
+    // neither can this
+    let mut iter = 1u32..20;
+    while let Some(x) = iter.next() {
+        println!("next: {:?}", iter.next());
+    }
+
+    // or this
+    let mut iter = 1u32..20;
+    while let Some(x) = iter.next() {
+        break;
+    }
+    println!("Remaining iter {:?}", iter);
+
+    // or this
+    let mut iter = 1u32..20;
+    while let Some(x) = iter.next() {
+        iter = 1..20;
+    }
+}
+
+// Issue #1188
+fn refutable() {
+    let a = [42, 1337];
+    let mut b = a.iter();
+
+    // consume all the 42s
+    while let Some(&42) = b.next() {}
+
+    let a = [(1, 2, 3)];
+    let mut b = a.iter();
+
+    while let Some(&(1, 2, 3)) = b.next() {}
+
+    let a = [Some(42)];
+    let mut b = a.iter();
+
+    while let Some(&None) = b.next() {}
+
+    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
+    for &42 in b {}
+    for &(1, 2, 3) in b {}
+    for &Option::None in b.next() {}
+    // */
+}
+
+fn nested_loops() {
+    let a = [42, 1337];
+    let mut y = a.iter();
+    loop {
+        // x is reused, so don't lint here
+        while let Some(v) = y.next() {}
+    }
+
+    let mut y = a.iter();
+    for _ in 0..2 {
+        while let Some(v) = y.next() {
+            // y is reused, don't lint
+        }
+    }
+
+    loop {
+        let mut y = a.iter();
+        while let Some(v) = y.next() {
+            // use a for loop here
+        }
+    }
+}
+
+fn issue1121() {
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(&value) = values.iter().next() {
+        values.remove(&value);
+    }
+}
+
+fn issue2965() {
+    // This should not cause an ICE and suggest:
+    //
+    // for _ in values.iter() {}
+    //
+    use std::collections::HashSet;
+    let mut values = HashSet::new();
+    values.insert(1);
+
+    while let Some(..) = values.iter().next() {
+        values.remove(&1);
+    }
+}
+
+fn issue3670() {
+    let array = [Some(0), None, Some(1)];
+    let mut iter = array.iter();
+
+    while let Some(elem) = iter.next() {
+        let _ = elem.or_else(|| *iter.next()?);
+    }
+}
diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr
new file mode 100644 (file)
index 0000000..03d2ef5
--- /dev/null
@@ -0,0 +1,34 @@
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:6:33
+   |
+LL |     while let Option::Some(x) = iter.next() {
+   |                                 ^^^^^^^^^^^ help: try: `for x in iter { .. }`
+   |
+   = note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:11:25
+   |
+LL |     while let Some(x) = iter.next() {
+   |                         ^^^^^^^^^^^ help: try: `for x in iter { .. }`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:16:25
+   |
+LL |     while let Some(_) = iter.next() {}
+   |                         ^^^^^^^^^^^ help: try: `for _ in iter { .. }`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:95:29
+   |
+LL |         while let Some(v) = y.next() {
+   |                             ^^^^^^^^ help: try: `for v in y { .. }`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:120:26
+   |
+LL |     while let Some(..) = values.iter().next() {
+   |                          ^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in values.iter() { .. }`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs
deleted file mode 100644 (file)
index 23a9ce8..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-
-
-
-#![warn(while_let_loop, empty_loop, while_let_on_iterator)]
-#![allow(dead_code, never_loop, unused, cyclomatic_complexity)]
-
-fn main() {
-    let y = Some(true);
-    loop {
-        if let Some(_x) = y {
-            let _v = 1;
-        } else {
-            break
-        }
-    }
-    loop { // no error, break is not in else clause
-        if let Some(_x) = y {
-            let _v = 1;
-        }
-        break;
-    }
-    loop {
-        match y {
-            Some(_x) => true,
-            None => break
-        };
-    }
-    loop {
-        let x = match y {
-            Some(x) => x,
-            None => break
-        };
-        let _x = x;
-        let _str = "foo";
-    }
-    loop {
-        let x = match y {
-            Some(x) => x,
-            None => break,
-        };
-        { let _a = "bar"; };
-        { let _b = "foobar"; }
-    }
-    loop { // no error, else branch does something other than break
-        match y {
-            Some(_x) => true,
-            _ => {
-                let _z = 1;
-                break;
-            }
-        };
-    }
-    while let Some(x) = y { // no error, obviously
-        println!("{}", x);
-    }
-
-    // #675, this used to have a wrong suggestion
-    loop {
-        let (e, l) = match "".split_whitespace().next() {
-            Some(word) => (word.is_empty(), word.len()),
-            None => break
-        };
-
-        let _ = (e, l);
-    }
-
-    let mut iter = 1..20;
-    while let Option::Some(x) = iter.next() {
-        println!("{}", x);
-    }
-
-    let mut iter = 1..20;
-    while let Some(x) = iter.next() {
-        println!("{}", x);
-    }
-
-    let mut iter = 1..20;
-    while let Some(_) = iter.next() {}
-
-    let mut iter = 1..20;
-    while let None = iter.next() {} // this is fine (if nonsensical)
-
-    let mut iter = 1..20;
-    if let Some(x) = iter.next() { // also fine
-        println!("{}", x)
-    }
-
-    // the following shouldn't warn because it can't be written with a for loop
-    let mut iter = 1u32..20;
-    while let Some(x) = iter.next() {
-        println!("next: {:?}", iter.next())
-    }
-
-    // neither can this
-    let mut iter = 1u32..20;
-    while let Some(x) = iter.next() {
-        println!("next: {:?}", iter.next());
-    }
-
-    // or this
-    let mut iter = 1u32..20;
-    while let Some(x) = iter.next() {break;}
-    println!("Remaining iter {:?}", iter);
-
-    // or this
-    let mut iter = 1u32..20;
-    while let Some(x) = iter.next() {
-        iter = 1..20;
-    }
-}
-
-// regression test (#360)
-// this should not panic
-// it's okay if further iterations of the lint
-// cause this function to trigger it
-fn no_panic<T>(slice: &[T]) {
-    let mut iter = slice.iter();
-    loop {
-        let _ = match iter.next() {
-            Some(ele) => ele,
-            None => break
-        };
-        loop {}
-    }
-}
-
-fn issue1017() {
-    let r: Result<u32, u32> = Ok(42);
-    let mut len = 1337;
-
-    loop {
-        match r {
-            Err(_) => len = 0,
-            Ok(length) => {
-                len = length;
-                break
-            }
-        }
-    }
-}
-
-// Issue #1188
-fn refutable() {
-    let a = [42, 1337];
-    let mut b = a.iter();
-
-    // consume all the 42s
-    while let Some(&42) = b.next() {
-    }
-
-    let a = [(1, 2, 3)];
-    let mut b = a.iter();
-
-    while let Some(&(1, 2, 3)) = b.next() {
-    }
-
-    let a = [Some(42)];
-    let mut b = a.iter();
-
-    while let Some(&None) = b.next() {
-    }
-
-    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
-    for &42 in b {}
-    for &(1, 2, 3) in b {}
-    for &Option::None in b.next() {}
-    // */
-
-    let mut y = a.iter();
-    loop { // x is reused, so don't lint here
-        while let Some(v) = y.next() {
-        }
-    }
-
-    let mut y = a.iter();
-    for _ in 0..2 {
-        while let Some(v) = y.next() { // y is reused, don't lint
-        }
-    }
-
-    loop {
-        let mut y = a.iter();
-        while let Some(v) = y.next() { // use a for loop here
-        }
-    }
-
-    // should not trigger while_let_loop lint because break passes an expression
-    let a = Some(10);
-    let b = loop {
-        if let Some(c) = a {
-            break Some(c);
-        } else {
-            break None;
-        }
-    };
-
-    use std::collections::HashSet;
-    let mut values = HashSet::new();
-    values.insert(1);
-
-    while let Some(&value) = values.iter().next() {
-        values.remove(&value);
-    }
-
-    // This should not cause an ICE and suggest:
-    //
-    // for _ in values.iter() {}
-    //
-    // See #2965
-    while let Some(..) = values.iter().next() {
-        values.remove(&1);
-    }
-}
diff --git a/tests/ui/while_loop.stderr b/tests/ui/while_loop.stderr
deleted file mode 100644 (file)
index d2b50b6..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-error: this loop could be written as a `while let` loop
-  --> $DIR/while_loop.rs:9:5
-   |
-9  | /     loop {
-10 | |         if let Some(_x) = y {
-11 | |             let _v = 1;
-12 | |         } else {
-13 | |             break
-14 | |         }
-15 | |     }
-   | |_____^ help: try: `while let Some(_x) = y { .. }`
-   |
-   = note: `-D while-let-loop` implied by `-D warnings`
-
-error: this loop could be written as a `while let` loop
-  --> $DIR/while_loop.rs:22:5
-   |
-22 | /     loop {
-23 | |         match y {
-24 | |             Some(_x) => true,
-25 | |             None => break
-26 | |         };
-27 | |     }
-   | |_____^ help: try: `while let Some(_x) = y { .. }`
-
-error: this loop could be written as a `while let` loop
-  --> $DIR/while_loop.rs:28:5
-   |
-28 | /     loop {
-29 | |         let x = match y {
-30 | |             Some(x) => x,
-31 | |             None => break
-...  |
-34 | |         let _str = "foo";
-35 | |     }
-   | |_____^ help: try: `while let Some(x) = y { .. }`
-
-error: this loop could be written as a `while let` loop
-  --> $DIR/while_loop.rs:36:5
-   |
-36 | /     loop {
-37 | |         let x = match y {
-38 | |             Some(x) => x,
-39 | |             None => break,
-...  |
-42 | |         { let _b = "foobar"; }
-43 | |     }
-   | |_____^ help: try: `while let Some(x) = y { .. }`
-
-error: this loop could be written as a `while let` loop
-  --> $DIR/while_loop.rs:58:5
-   |
-58 | /     loop {
-59 | |         let (e, l) = match "".split_whitespace().next() {
-60 | |             Some(word) => (word.is_empty(), word.len()),
-61 | |             None => break
-...  |
-64 | |         let _ = (e, l);
-65 | |     }
-   | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }`
-
-error: this loop could be written as a `for` loop
-  --> $DIR/while_loop.rs:68:33
-   |
-68 |     while let Option::Some(x) = iter.next() {
-   |                                 ^^^^^^^^^^^ help: try: `for x in iter { .. }`
-   |
-   = note: `-D while-let-on-iterator` implied by `-D warnings`
-
-error: this loop could be written as a `for` loop
-  --> $DIR/while_loop.rs:73:25
-   |
-73 |     while let Some(x) = iter.next() {
-   |                         ^^^^^^^^^^^ help: try: `for x in iter { .. }`
-
-error: this loop could be written as a `for` loop
-  --> $DIR/while_loop.rs:78:25
-   |
-78 |     while let Some(_) = iter.next() {}
-   |                         ^^^^^^^^^^^ help: try: `for _ in iter { .. }`
-
-error: this loop could be written as a `while let` loop
-   --> $DIR/while_loop.rs:118:5
-    |
-118 | /     loop {
-119 | |         let _ = match iter.next() {
-120 | |             Some(ele) => ele,
-121 | |             None => break
-122 | |         };
-123 | |         loop {}
-124 | |     }
-    | |_____^ help: try: `while let Some(ele) = iter.next() { .. }`
-
-error: empty `loop {}` detected. You may want to either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
-   --> $DIR/while_loop.rs:123:9
-    |
-123 |         loop {}
-    |         ^^^^^^^
-    |
-    = note: `-D empty-loop` implied by `-D warnings`
-
-error: this loop could be written as a `for` loop
-   --> $DIR/while_loop.rs:183:29
-    |
-183 |         while let Some(v) = y.next() { // use a for loop here
-    |                             ^^^^^^^^ help: try: `for v in y { .. }`
-
-error: this loop could be written as a `for` loop
-   --> $DIR/while_loop.rs:210:26
-    |
-210 |     while let Some(..) = values.iter().next() {
-    |                          ^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in values.iter() { .. }`
-
-error: aborting due to 12 previous errors
-
diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs
new file mode 100644 (file)
index 0000000..94d69d3
--- /dev/null
@@ -0,0 +1,62 @@
+#![deny(clippy::wildcard_enum_match_arm)]
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+enum Color {
+    Red,
+    Green,
+    Blue,
+    Rgb(u8, u8, u8),
+    Cyan,
+}
+
+impl Color {
+    fn is_monochrome(self) -> bool {
+        match self {
+            Color::Red | Color::Green | Color::Blue => true,
+            Color::Rgb(r, g, b) => r | g == 0 || r | b == 0 || g | b == 0,
+            Color::Cyan => false,
+        }
+    }
+}
+
+fn main() {
+    let color = Color::Rgb(0, 0, 127);
+    match color {
+        Color::Red => println!("Red"),
+        _ => eprintln!("Not red"),
+    };
+    match color {
+        Color::Red => println!("Red"),
+        _not_red => eprintln!("Not red"),
+    };
+    let _str = match color {
+        Color::Red => "Red".to_owned(),
+        not_red => format!("{:?}", not_red),
+    };
+    match color {
+        Color::Red => {},
+        Color::Green => {},
+        Color::Blue => {},
+        Color::Cyan => {},
+        c if c.is_monochrome() => {},
+        Color::Rgb(_, _, _) => {},
+    };
+    let _str = match color {
+        Color::Red => "Red",
+        c @ Color::Green | c @ Color::Blue | c @ Color::Rgb(_, _, _) | c @ Color::Cyan => "Not red",
+    };
+    match color {
+        Color::Rgb(r, _, _) if r > 0 => "Some red",
+        _ => "No red",
+    };
+    match color {
+        Color::Red | Color::Green | Color::Blue | Color::Cyan => {},
+        Color::Rgb(..) => {},
+    };
+    let x: u8 = unimplemented!();
+    match x {
+        0 => {},
+        140 => {},
+        _ => {},
+    };
+}
diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr
new file mode 100644 (file)
index 0000000..999c169
--- /dev/null
@@ -0,0 +1,32 @@
+error: wildcard match will miss any future added variants.
+  --> $DIR/wildcard_enum_match_arm.rs:26:9
+   |
+LL |         _ => eprintln!("Not red"),
+   |         ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
+   |
+note: lint level defined here
+  --> $DIR/wildcard_enum_match_arm.rs:1:9
+   |
+LL | #![deny(clippy::wildcard_enum_match_arm)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: wildcard match will miss any future added variants.
+  --> $DIR/wildcard_enum_match_arm.rs:30:9
+   |
+LL |         _not_red => eprintln!("Not red"),
+   |         ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
+
+error: wildcard match will miss any future added variants.
+  --> $DIR/wildcard_enum_match_arm.rs:34:9
+   |
+LL |         not_red => format!("{:?}", not_red),
+   |         ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
+
+error: wildcard match will miss any future added variants.
+  --> $DIR/wildcard_enum_match_arm.rs:50:9
+   |
+LL |         _ => "No red",
+   |         ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
+
+error: aborting due to 4 previous errors
+
index 48dfcd0ea3e11d9d3fa7326a16971f0fb0edfcc2..d8205c5eb670009189596bac1e39453d0277aa35 100644 (file)
@@ -1,5 +1,5 @@
 #![allow(unused_must_use)]
-#![warn(write_literal)]
+#![warn(clippy::write_literal)]
 
 use std::io::Write;
 
@@ -11,17 +11,17 @@ fn main() {
     writeln!(&mut v, "Hello");
     let world = "world";
     writeln!(&mut v, "Hello {}", world);
-    writeln!(&mut v, "Hello {world}", world=world);
+    writeln!(&mut v, "Hello {world}", world = world);
     writeln!(&mut v, "3 in hex is {:X}", 3);
     writeln!(&mut v, "2 + 1 = {:.4}", 3);
     writeln!(&mut v, "2 + 1 = {:5.4}", 3);
     writeln!(&mut v, "Debug test {:?}", "hello, world");
     writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
     writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
-    writeln!(&mut v, "{foo:8} {bar:>8}", foo="hello", bar="world");
-    writeln!(&mut v, "{bar:8} {foo:>8}", foo="hello", bar="world");
-    writeln!(&mut v, "{number:>width$}", number=1, width=6);
-    writeln!(&mut v, "{number:>0width$}", number=1, width=6);
+    writeln!(&mut v, "{foo:8} {bar:>8}", foo = "hello", bar = "world");
+    writeln!(&mut v, "{bar:8} {foo:>8}", foo = "hello", bar = "world");
+    writeln!(&mut v, "{number:>width$}", number = 1, width = 6);
+    writeln!(&mut v, "{number:>0width$}", number = 1, width = 6);
 
     // these should throw warnings
     writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
@@ -38,6 +38,6 @@ fn main() {
     writeln!(&mut v, "{1} {0}", "hello", "world");
 
     // named args shouldn't change anything either
-    writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
-    writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
+    writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
+    writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
 }
index d2e8ca94ed807938580479d716700932a17c14c8..54a787fe555af67960403da0c0317714bc731a43 100644 (file)
@@ -1,88 +1,88 @@
 error: literal with an empty format string
   --> $DIR/write_literal.rs:27:79
    |
-27 |     writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
+LL |     writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
    |                                                                               ^
    |
-   = note: `-D write-literal` implied by `-D warnings`
+   = note: `-D clippy::write-literal` implied by `-D warnings`
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:28:32
    |
-28 |     write!(&mut v, "Hello {}", "world");
+LL |     write!(&mut v, "Hello {}", "world");
    |                                ^^^^^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:29:44
    |
-29 |     writeln!(&mut v, "Hello {} {}", world, "world");
+LL |     writeln!(&mut v, "Hello {} {}", world, "world");
    |                                            ^^^^^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:30:34
    |
-30 |     writeln!(&mut v, "Hello {}", "world");
+LL |     writeln!(&mut v, "Hello {}", "world");
    |                                  ^^^^^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:31:38
    |
-31 |     writeln!(&mut v, "10 / 4 is {}", 2.5);
+LL |     writeln!(&mut v, "10 / 4 is {}", 2.5);
    |                                      ^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:32:36
    |
-32 |     writeln!(&mut v, "2 + 1 = {}", 3);
+LL |     writeln!(&mut v, "2 + 1 = {}", 3);
    |                                    ^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:37:33
    |
-37 |     writeln!(&mut v, "{0} {1}", "hello", "world");
+LL |     writeln!(&mut v, "{0} {1}", "hello", "world");
    |                                 ^^^^^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:37:42
    |
-37 |     writeln!(&mut v, "{0} {1}", "hello", "world");
+LL |     writeln!(&mut v, "{0} {1}", "hello", "world");
    |                                          ^^^^^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:38:33
    |
-38 |     writeln!(&mut v, "{1} {0}", "hello", "world");
+LL |     writeln!(&mut v, "{1} {0}", "hello", "world");
    |                                 ^^^^^^^
 
 error: literal with an empty format string
   --> $DIR/write_literal.rs:38:42
    |
-38 |     writeln!(&mut v, "{1} {0}", "hello", "world");
+LL |     writeln!(&mut v, "{1} {0}", "hello", "world");
    |                                          ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:41:41
+  --> $DIR/write_literal.rs:41:43
    |
-41 |     writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
-   |                                         ^^^^^^^
+LL |     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
+   |                                           ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:41:54
+  --> $DIR/write_literal.rs:41:58
    |
-41 |     writeln!(&mut v, "{foo} {bar}", foo="hello", bar="world");
-   |                                                      ^^^^^^^
+LL |     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
+   |                                                          ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:42:41
+  --> $DIR/write_literal.rs:42:43
    |
-42 |     writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
-   |                                         ^^^^^^^
+LL |     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
+   |                                           ^^^^^^^
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:42:54
+  --> $DIR/write_literal.rs:42:58
    |
-42 |     writeln!(&mut v, "{bar} {foo}", foo="hello", bar="world");
-   |                                                      ^^^^^^^
+LL |     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
+   |                                                          ^^^^^^^
 
 error: aborting due to 14 previous errors
 
index 0427bd3ec04a6cadb84f1ab7745da5789afd6380..dd80dc0cf9c5e4cd04e853f324699742d0dbeb08 100644 (file)
@@ -1,5 +1,5 @@
-#![allow(write_literal)]
-#![warn(write_with_newline)]
+#![allow(clippy::write_literal)]
+#![warn(clippy::write_with_newline)]
 
 use std::io::Write;
 
@@ -9,7 +9,7 @@ fn main() {
     // These should fail
     write!(&mut v, "Hello\n");
     write!(&mut v, "Hello {}\n", "world");
-    write!(&mut v, "Hello {} {}\n\n", "world", "#2");
+    write!(&mut v, "Hello {} {}\n", "world", "#2");
     write!(&mut v, "{}\n", 1265);
 
     // These should be fine
@@ -21,5 +21,29 @@ fn main() {
     write!(&mut v, "Issue\n{}", 1265);
     write!(&mut v, "{}", 1265);
     write!(&mut v, "\n{}", 1275);
+    write!(&mut v, "\n\n");
+    write!(&mut v, "like eof\n\n");
+    write!(&mut v, "Hello {} {}\n\n", "world", "#2");
+    writeln!(&mut v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
+    writeln!(&mut v, "\nbla\n\n"); // #3126
+
+    // Escaping
+    write!(&mut v, "\\n"); // #3514
+    write!(&mut v, "\\\n"); // should fail
+    write!(&mut v, "\\\\n");
+
+    // Raw strings
+    write!(&mut v, r"\n"); // #3778
 
+    // Literal newlines should also fail
+    write!(
+        &mut v,
+        "
+"
+    );
+    write!(
+        &mut v,
+        r"
+"
+    );
 }
index 7bb9b99731ffb7740a3753ac6c6c73be20174f0f..3a31f61a277cfe93814a356ea305b6b505ce159f 100644 (file)
@@ -1,28 +1,54 @@
-error: using `write!()` with a format string that ends in a newline, consider using `writeln!()` instead
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
   --> $DIR/write_with_newline.rs:10:5
    |
-10 |     write!(&mut v, "Hello/n");
+LL |     write!(&mut v, "Hello/n");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `-D write-with-newline` implied by `-D warnings`
+   = note: `-D clippy::write-with-newline` implied by `-D warnings`
 
-error: using `write!()` with a format string that ends in a newline, consider using `writeln!()` instead
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
   --> $DIR/write_with_newline.rs:11:5
    |
-11 |     write!(&mut v, "Hello {}/n", "world");
+LL |     write!(&mut v, "Hello {}/n", "world");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: using `write!()` with a format string that ends in a newline, consider using `writeln!()` instead
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
   --> $DIR/write_with_newline.rs:12:5
    |
-12 |     write!(&mut v, "Hello {} {}/n/n", "world", "#2");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(&mut v, "Hello {} {}/n", "world", "#2");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: using `write!()` with a format string that ends in a newline, consider using `writeln!()` instead
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
   --> $DIR/write_with_newline.rs:13:5
    |
-13 |     write!(&mut v, "{}/n", 1265);
+LL |     write!(&mut v, "{}/n", 1265);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
+  --> $DIR/write_with_newline.rs:32:5
+   |
+LL |     write!(&mut v, "//n"); // should fail
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
+  --> $DIR/write_with_newline.rs:39:5
+   |
+LL | /     write!(
+LL | |         &mut v,
+LL | |         "
+LL | | "
+LL | |     );
+   | |_____^
+
+error: using `write!()` with a format string that ends in a single newline, consider using `writeln!()` instead
+  --> $DIR/write_with_newline.rs:44:5
+   |
+LL | /     write!(
+LL | |         &mut v,
+LL | |         r"
+LL | | "
+LL | |     );
+   | |_____^
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/writeln_empty_string.fixed b/tests/ui/writeln_empty_string.fixed
new file mode 100644 (file)
index 0000000..c3ac15b
--- /dev/null
@@ -0,0 +1,20 @@
+// run-rustfix
+
+#![allow(unused_must_use)]
+#![warn(clippy::writeln_empty_string)]
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+
+    // These should fail
+    writeln!(&mut v);
+
+    let mut suggestion = Vec::new();
+    writeln!(&mut suggestion);
+
+    // These should be fine
+    writeln!(&mut v);
+    writeln!(&mut v, " ");
+    write!(&mut v, "");
+}
index c7092eb8c4b00fbdaf6df8131558856a4dc3cf69..9a8894b6c0d3285b2a3a07ed6b7ecdaec4094658 100644 (file)
@@ -1,16 +1,20 @@
+// run-rustfix
+
 #![allow(unused_must_use)]
-#![warn(writeln_empty_string)]
+#![warn(clippy::writeln_empty_string)]
 use std::io::Write;
 
 fn main() {
     let mut v = Vec::new();
 
-    // This should fail
+    // These should fail
     writeln!(&mut v, "");
 
+    let mut suggestion = Vec::new();
+    writeln!(&mut suggestion, "");
+
     // These should be fine
     writeln!(&mut v);
     writeln!(&mut v, " ");
     write!(&mut v, "");
-
 }
index 16a8e0a203d3a3f26cea4c32e025710d79015bc7..99635229b3e13eafc1f4bf2db210de1e677215a0 100644 (file)
@@ -1,10 +1,16 @@
-error: using `writeln!(v, "")`
--> $DIR/writeln_empty_string.rs:9:5
-  |
-9 |     writeln!(&mut v, "");
-  |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)`
-  |
-  = note: `-D writeln-empty-string` implied by `-D warnings`
+error: using `writeln!(&mut v, "")`
 --> $DIR/writeln_empty_string.rs:11:5
+   |
+LL |     writeln!(&mut v, "");
+   |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut v)`
+   |
+   = note: `-D clippy::writeln-empty-string` implied by `-D warnings`
 
-error: aborting due to previous error
+error: using `writeln!(&mut suggestion, "")`
+  --> $DIR/writeln_empty_string.rs:14:5
+   |
+LL |     writeln!(&mut suggestion, "");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut suggestion)`
+
+error: aborting due to 2 previous errors
 
index 07a93d6889bf0cc1787cf751323fa113d254b4fe..bdffb5af87e6a0449f5d8d0c620f7154fdb88983 100644 (file)
@@ -1,9 +1,6 @@
-
-
-
-#![warn(wrong_self_convention)]
-#![warn(wrong_pub_self_convention)]
-#![allow(dead_code, trivially_copy_pass_by_ref)]
+#![warn(clippy::wrong_self_convention)]
+#![warn(clippy::wrong_pub_self_convention)]
+#![allow(dead_code, clippy::trivially_copy_pass_by_ref)]
 
 fn main() {}
 
@@ -11,7 +8,6 @@ fn main() {}
 struct Foo;
 
 impl Foo {
-
     fn as_i32(self) {}
     fn as_u32(&self) {}
     fn into_i32(self) {}
@@ -26,17 +22,16 @@ pub fn is_i64(self) {}
     pub fn to_i64(self) {}
     pub fn from_i64(self) {}
     // check whether the lint can be allowed at the function level
-    #[allow(wrong_self_convention)]
+    #[allow(clippy::wrong_self_convention)]
     pub fn from_cake(self) {}
 
-    fn as_x<F: AsRef<Self>>(_: F) { }
-    fn as_y<F: AsRef<Foo>>(_: F) { }
+    fn as_x<F: AsRef<Self>>(_: F) {}
+    fn as_y<F: AsRef<Foo>>(_: F) {}
 }
 
 struct Bar;
 
 impl Bar {
-
     fn as_i32(self) {}
     fn as_u32(&self) {}
     fn into_i32(&self) {}
@@ -59,4 +54,5 @@ fn into_(&self) {}
     fn is_(self) {}
     fn to_(self) {}
     fn from_(self) {}
+    fn to_mut(&mut self) {}
 }
index 216fd0bb82b8907fe9b2795951a1e28996ceeea3..0d0eb19cd072333012d91cc384e5b6a2031e199a 100644 (file)
@@ -1,75 +1,75 @@
 error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:21:17
+  --> $DIR/wrong_self_convention.rs:17:17
    |
-21 |     fn from_i32(self) {}
+LL |     fn from_i32(self) {}
    |                 ^^^^
    |
-   = note: `-D wrong-self-convention` implied by `-D warnings`
+   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
 
 error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:27:21
+  --> $DIR/wrong_self_convention.rs:23:21
    |
-27 |     pub fn from_i64(self) {}
+LL |     pub fn from_i64(self) {}
    |                     ^^^^
 
 error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:40:15
+  --> $DIR/wrong_self_convention.rs:35:15
    |
-40 |     fn as_i32(self) {}
+LL |     fn as_i32(self) {}
    |               ^^^^
 
 error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:42:17
+  --> $DIR/wrong_self_convention.rs:37:17
    |
-42 |     fn into_i32(&self) {}
+LL |     fn into_i32(&self) {}
    |                 ^^^^^
 
 error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:44:15
+  --> $DIR/wrong_self_convention.rs:39:15
    |
-44 |     fn is_i32(self) {}
+LL |     fn is_i32(self) {}
    |               ^^^^
 
 error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:46:15
+  --> $DIR/wrong_self_convention.rs:41:15
    |
-46 |     fn to_i32(self) {}
+LL |     fn to_i32(self) {}
    |               ^^^^
 
 error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:48:17
+  --> $DIR/wrong_self_convention.rs:43:17
    |
-48 |     fn from_i32(self) {}
+LL |     fn from_i32(self) {}
    |                 ^^^^
 
 error: methods called `as_*` usually take self by reference or self by mutable reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:50:19
+  --> $DIR/wrong_self_convention.rs:45:19
    |
-50 |     pub fn as_i64(self) {}
+LL |     pub fn as_i64(self) {}
    |                   ^^^^
 
 error: methods called `into_*` usually take self by value; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:51:21
+  --> $DIR/wrong_self_convention.rs:46:21
    |
-51 |     pub fn into_i64(&self) {}
+LL |     pub fn into_i64(&self) {}
    |                     ^^^^^
 
 error: methods called `is_*` usually take self by reference or no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:52:19
+  --> $DIR/wrong_self_convention.rs:47:19
    |
-52 |     pub fn is_i64(self) {}
+LL |     pub fn is_i64(self) {}
    |                   ^^^^
 
 error: methods called `to_*` usually take self by reference; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:53:19
+  --> $DIR/wrong_self_convention.rs:48:19
    |
-53 |     pub fn to_i64(self) {}
+LL |     pub fn to_i64(self) {}
    |                   ^^^^
 
 error: methods called `from_*` usually take no self; consider choosing a less ambiguous name
-  --> $DIR/wrong_self_convention.rs:54:21
+  --> $DIR/wrong_self_convention.rs:49:21
    |
-54 |     pub fn from_i64(self) {}
+LL |     pub fn from_i64(self) {}
    |                     ^^^^
 
 error: aborting due to 12 previous errors
index 65e1e2399803aee422833a5b720753c619d093a5..09db130a764315b5c2227c928d5c637cdbef6a71 100644 (file)
@@ -1,16 +1,13 @@
-
-
-
 #[allow(unused_variables)]
-#[warn(zero_divided_by_zero)]
+#[warn(clippy::zero_divided_by_zero)]
 fn main() {
     let nan = 0.0 / 0.0;
     let f64_nan = 0.0 / 0.0f64;
     let other_f64_nan = 0.0f64 / 0.0;
-    let one_more_f64_nan = 0.0f64/0.0f64;
+    let one_more_f64_nan = 0.0f64 / 0.0f64;
     let zero = 0.0;
     let other_zero = 0.0;
     let other_nan = zero / other_zero; // fine - this lint doesn't propegate constants.
-    let not_nan = 2.0/0.0; // not an error: 2/0 = inf
-    let also_not_nan = 0.0/2.0; // not an error: 0/2 = 0
+    let not_nan = 2.0 / 0.0; // not an error: 2/0 = inf
+    let also_not_nan = 0.0 / 2.0; // not an error: 0/2 = 0
 }
index f1788fc9ec516cc4659932abb7dfd942fa118998..763859f54fb22cf6a9d0cfc4d86ea53c3dc037e9 100644 (file)
@@ -1,59 +1,59 @@
 error: equal expressions as operands to `/`
--> $DIR/zero_div_zero.rs:7:15
-  |
-7 |     let nan = 0.0 / 0.0;
-  |               ^^^^^^^^^
-  |
-  = note: #[deny(eq_op)] on by default
 --> $DIR/zero_div_zero.rs:4:15
+   |
+LL |     let nan = 0.0 / 0.0;
+   |               ^^^^^^^^^
+   |
+   = note: #[deny(clippy::eq_op)] on by default
 
 error: constant division of 0.0 with 0.0 will always result in NaN
--> $DIR/zero_div_zero.rs:7:15
-  |
-7 |     let nan = 0.0 / 0.0;
-  |               ^^^^^^^^^
-  |
-  = note: `-D zero-divided-by-zero` implied by `-D warnings`
-  = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 --> $DIR/zero_div_zero.rs:4:15
+   |
+LL |     let nan = 0.0 / 0.0;
+   |               ^^^^^^^^^
+   |
+   = note: `-D clippy::zero-divided-by-zero` implied by `-D warnings`
+   = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 
 error: equal expressions as operands to `/`
--> $DIR/zero_div_zero.rs:8:19
-  |
-8 |     let f64_nan = 0.0 / 0.0f64;
-  |                   ^^^^^^^^^^^^
 --> $DIR/zero_div_zero.rs:5:19
+   |
+LL |     let f64_nan = 0.0 / 0.0f64;
+   |                   ^^^^^^^^^^^^
 
 error: constant division of 0.0 with 0.0 will always result in NaN
--> $DIR/zero_div_zero.rs:8:19
-  |
-8 |     let f64_nan = 0.0 / 0.0f64;
-  |                   ^^^^^^^^^^^^
-  |
-  = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 --> $DIR/zero_div_zero.rs:5:19
+   |
+LL |     let f64_nan = 0.0 / 0.0f64;
+   |                   ^^^^^^^^^^^^
+   |
+   = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 
 error: equal expressions as operands to `/`
--> $DIR/zero_div_zero.rs:9:25
-  |
-9 |     let other_f64_nan = 0.0f64 / 0.0;
-  |                         ^^^^^^^^^^^^
 --> $DIR/zero_div_zero.rs:6:25
+   |
+LL |     let other_f64_nan = 0.0f64 / 0.0;
+   |                         ^^^^^^^^^^^^
 
 error: constant division of 0.0 with 0.0 will always result in NaN
--> $DIR/zero_div_zero.rs:9:25
-  |
-9 |     let other_f64_nan = 0.0f64 / 0.0;
-  |                         ^^^^^^^^^^^^
-  |
-  = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 --> $DIR/zero_div_zero.rs:6:25
+   |
+LL |     let other_f64_nan = 0.0f64 / 0.0;
+   |                         ^^^^^^^^^^^^
+   |
+   = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 
 error: equal expressions as operands to `/`
-  --> $DIR/zero_div_zero.rs:10:28
+  --> $DIR/zero_div_zero.rs:7:28
    |
-10 |     let one_more_f64_nan = 0.0f64/0.0f64;
-   |                            ^^^^^^^^^^^^^
+LL |     let one_more_f64_nan = 0.0f64 / 0.0f64;
+   |                            ^^^^^^^^^^^^^^^
 
 error: constant division of 0.0 with 0.0 will always result in NaN
-  --> $DIR/zero_div_zero.rs:10:28
+  --> $DIR/zero_div_zero.rs:7:28
    |
-10 |     let one_more_f64_nan = 0.0f64/0.0f64;
-   |                            ^^^^^^^^^^^^^
+LL |     let one_more_f64_nan = 0.0f64 / 0.0f64;
+   |                            ^^^^^^^^^^^^^^^
    |
    = help: Consider using `std::f64::NAN` if you would like a constant representing NaN
 
index 4a6010f4bd0b3a28e178fd834f268a6db6cc7902..2291c77d56e67a8cd888a95ce60d21eb3735209f 100644 (file)
@@ -1,6 +1,3 @@
-
-
-
 #[allow(unused_variables)]
 fn main() {
     let x = 0 as *const usize;
index 5155dc401bd112ae61ee9863588dce6e7dad8873..b79c3457b9b31a2bebba244fdf7eea438855a1f7 100644 (file)
@@ -1,16 +1,16 @@
 error: `0 as *const _` detected. Consider using `ptr::null()`
--> $DIR/zero_ptr.rs:6:13
-  |
-6 |     let x = 0 as *const usize;
-  |             ^^^^^^^^^^^^^^^^^
-  |
-  = note: `-D zero-ptr` implied by `-D warnings`
 --> $DIR/zero_ptr.rs:3:13
+   |
+LL |     let x = 0 as *const usize;
+   |             ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::zero-ptr` implied by `-D warnings`
 
 error: `0 as *mut _` detected. Consider using `ptr::null_mut()`
--> $DIR/zero_ptr.rs:7:13
-  |
-7 |     let y = 0 as *mut f64;
-  |             ^^^^^^^^^^^^^
 --> $DIR/zero_ptr.rs:4:13
+   |
+LL |     let y = 0 as *mut f64;
+   |             ^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 25b0ceefae72f6596c6462c040dd7e2c9c57cb4f..f5d03c645df0435b7876033306ef910f0237afcc 100644 (file)
@@ -1,19 +1,18 @@
-extern crate cargo_metadata;
-extern crate semver;
-use semver::VersionReq;
-
 #[test]
 fn check_that_clippy_lints_has_the_same_version_as_clippy() {
-    let clippy_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata");
+    let clippy_meta = cargo_metadata::MetadataCommand::new()
+        .no_deps()
+        .exec()
+        .expect("could not obtain cargo metadata");
     std::env::set_current_dir(std::env::current_dir().unwrap().join("clippy_lints")).unwrap();
-    let clippy_lints_meta = cargo_metadata::metadata(None).expect("could not obtain cargo metadata");
+    let clippy_lints_meta = cargo_metadata::MetadataCommand::new()
+        .no_deps()
+        .exec()
+        .expect("could not obtain cargo metadata");
     assert_eq!(clippy_lints_meta.packages[0].version, clippy_meta.packages[0].version);
     for package in &clippy_meta.packages[0].dependencies {
         if package.name == "clippy_lints" {
-            assert_eq!(
-                VersionReq::parse(&clippy_lints_meta.packages[0].version).unwrap(),
-                package.req
-            );
+            assert!(package.req.matches(&clippy_lints_meta.packages[0].version));
             return;
         }
     }
diff --git a/tests/without_block_comments.rs b/tests/without_block_comments.rs
deleted file mode 100644 (file)
index 730c5cb..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-extern crate clippy_lints;
-use clippy_lints::utils::without_block_comments;
-
-#[test]
-fn test_lines_without_block_comments() {
-    let result = without_block_comments(vec!["/*", "", "*/"]);
-    println!("result: {:?}", result);
-    assert!(result.is_empty());
-
-    let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
-    assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
-
-    let result = without_block_comments(vec!["/* rust", "", "*/"]);
-    assert!(result.is_empty());
-
-    let result = without_block_comments(vec!["/* one-line comment */"]);
-    assert!(result.is_empty());
-
-    let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
-    assert!(result.is_empty());
-
-    let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
-    assert!(result.is_empty());
-
-    let result = without_block_comments(vec!["foo", "bar", "baz"]);
-    assert_eq!(result, vec!["foo", "bar", "baz"]);
-}
diff --git a/util/dev b/util/dev
new file mode 100755 (executable)
index 0000000..4fa6e69
--- /dev/null
+++ b/util/dev
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+cd clippy_dev && cargo run -- $@
diff --git a/util/dogfood.sh b/util/dogfood.sh
deleted file mode 100755 (executable)
index 358fc46..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-rm -rf target*/*so
-cargo build --lib && cp -R target target_recur && cargo rustc --lib -- -Zextra-plugins=clippy -Ltarget_recur/debug -Dclippy_pedantic -Dclippy || exit 1
-rm -rf target_recur
-
index 5419624d48e54fe5703954943e0fbe2c3f3d5e90..827b1e31905c31b52b85901892f372781e2331e7 100755 (executable)
@@ -1,4 +1,5 @@
 #!/usr/bin/env python
+
 # Build the gh-pages
 
 import re
diff --git a/util/fetch_prs_between.sh b/util/fetch_prs_between.sh
new file mode 100755 (executable)
index 0000000..dbe73b1
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Fetches the merge commits between two git commits and prints the PR URL
+# together with the full commit message
+#
+# If you want to use this to update the Clippy changelog, be sure to manually
+# exclude the non-user facing changes like 'rustup' PRs, typo fixes, etc.
+
+first=$1
+last=$2
+
+IFS='
+'
+for pr in $(git log --oneline --grep "Merge #" --grep "Merge pull request" --grep "Auto merge of" "$first...$last" | sort -rn | uniq); do
+  id=$(echo $pr | rg -o '#[0-9]{3,5}' | cut -c 2-)
+  commit=$(echo $pr | cut -d' ' -f 1)
+  echo "URL: https://github.com/rust-lang/rust-clippy/pull/$id"
+  echo "$(git --no-pager show --pretty=medium $commit)"
+  echo "---------------------------------------------------------\n"
+done
index 0088ecc3d89ddc699c3a94c711a5526eed998568..e11f2eeba3b32d11e5cd64b72a10b4c44498132c 100644 (file)
@@ -4,7 +4,7 @@
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
 
-    <title>Clippy</title>
+    <title>ALL the Clippy Lints</title>
 
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/styles/github.min.css"/>
@@ -14,7 +14,7 @@
 
         .form-inline .checkbox { margin-right: 0.6em }
 
-        .panel-heading { pointer: cursor; }
+        .panel-heading { cursor: pointer; }
         .panel-heading:hover { background-color: #eee; }
 
         .panel-title { display: flex; }
@@ -76,8 +76,8 @@
                 <div class="panel-body row">
                     <div class="col-md-12 form-horizontal">
                         <div class="input-group">
-                            <span class="input-group-addon" id="filter-label">Filter:</span>
-                            <input type="text" class="form-control" placeholder="Keywords or search string" aria-describedby="filter-label" ng-model="search" />
+                            <label class="input-group-addon" id="filter-label" for="filter-input">Filter:</label>
+                            <input type="text" class="form-control" placeholder="Keywords or search string" id="filter-input" ng-model="search" />
                             <span class="input-group-btn">
                                 <button class="btn btn-default" type="button" ng-click="search = ''">
                                     Clear
         </div>
     </div>
 
-    <a href="https://github.com/rust-lang-nursery/rust-clippy">
+    <a href="https://github.com/rust-lang/rust-clippy">
         <img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on Github"/>
     </a>
 
             });
         }
 
+        function selectGroup($scope, selectedGroup) {
+            var groups = $scope.groups;
+            for (var group in groups) {
+                if (groups.hasOwnProperty(group)) {
+                    if (group === selectedGroup) {
+                        groups[group] = true;
+                    } else {
+                        groups[group] = false;
+                    }
+                }
+            }
+        }
+
         angular.module("clippy", [])
         .filter('markdown', function ($sce) {
             return function (text) {
                     return result;
                 }, {});
 
+                var selectedGroup = getQueryVariable("sel");
+                if (selectedGroup) {
+                    selectGroup($scope, selectedGroup.toLowerCase());
+                }
+
                 scrollToLintByURL($scope);
             })
             .error(function (data) {
             }, false);
         });
     })();
+
+    function getQueryVariable(variable) {
+        var query = window.location.search.substring(1);
+        var vars = query.split('&');
+        for (var i = 0; i < vars.length; i++) {
+            var pair = vars[i].split('=');
+            if (decodeURIComponent(pair[0]) == variable) {
+                return decodeURIComponent(pair[1]);
+            }
+        }
+    }
     </script>
 </body>
 </html>
index 5678ebec7220c916dd2551e779c52dd5483b15dc..391e22a4743ccdcd739f536304cf6736c63a609d 100644 (file)
@@ -4,7 +4,7 @@
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1"/>
 
-    <title>Clippy</title>
+    <title>Clippy lints documentation</title>
 
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css"/>
     <style>
@@ -43,7 +43,7 @@
         </div>
     </div>
 
-    <a href="https://github.com/rust-lang-nursery/rust-clippy">
+    <a href="https://github.com/rust-lang/rust-clippy">
         <img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"/>
     </a>
 
index 00826805e1617b5e80db08168b668f8e1f5b087d..a260e00cde460ad200a08dcd3470ba745e2f0ae4 100644 (file)
@@ -15,6 +15,7 @@ group_re = re.compile(r'''\s*([a-z_][a-z_0-9]+)''')
 conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
 confvar_re = re.compile(
     r'''/// Lint: (\w+). (.*).*\n\s*\([^,]+,\s+"([^"]+)",\s+([^=\)]+)=>\s+(.*)\),''', re.MULTILINE)
+comment_re = re.compile(r'''\s*/// ?(.*)''')
 
 lint_levels = {
     "correctness": 'Deny',
@@ -29,37 +30,15 @@ lint_levels = {
 
 
 def parse_lints(lints, filepath):
-    last_comment = []
-    comment = True
+    comment = []
     clippy = False
     deprecated = False
     name = ""
 
     with open(filepath) as fp:
         for line in fp:
-            if comment:
-                if line.startswith("/// "):
-                    last_comment.append(line[4:])
-                elif line.startswith("///"):
-                    last_comment.append(line[3:])
-                elif line.startswith("declare_lint!"):
-                    import sys
-                    print "don't use `declare_lint!` in Clippy, use `declare_clippy_lint!` instead"
-                    sys.exit(42)
-                elif line.startswith("declare_clippy_lint!"):
-                    comment = False
-                    deprecated = False
-                    clippy = True
-                    name = ""
-                elif line.startswith("declare_deprecated_lint!"):
-                    comment = False
-                    deprecated = True
-                    clippy = False
-                else:
-                    last_comment = []
-            if not comment:
+            if clippy or deprecated:
                 m = lintname_re.search(line)
-
                 if m:
                     name = m.group(1).lower()
                     line = next(fp)
@@ -72,19 +51,38 @@ def parse_lints(lints, filepath):
                             g = group_re.search(line)
                             if g:
                                 group = g.group(1).lower()
-                                level = lint_levels[group]
+                                level = lint_levels.get(group, None)
                                 break
                             line = next(fp)
 
+                    if level is None:
+                        continue
+
                     log.info("found %s with level %s in %s",
                              name, level, filepath)
-                    lints.append(Lint(name, level, last_comment, filepath, group))
-                    last_comment = []
-                    comment = True
+                    lints.append(Lint(name, level, comment, filepath, group))
+                    comment = []
 
-                    if "}" in line:
-                        log.warn("Warning: missing Lint-Name in %s", filepath)
-                        comment = True
+                    clippy = False
+                    deprecated = False
+                    name = ""
+                else:
+                    m = comment_re.search(line)
+                    if m:
+                        comment.append(m.group(1))
+            elif line.startswith("declare_clippy_lint!"):
+                clippy = True
+                deprecated = False
+            elif line.startswith("declare_deprecated_lint!"):
+                clippy = False
+                deprecated = True
+            elif line.startswith("declare_lint!"):
+                import sys
+                print(
+                    "don't use `declare_lint!` in Clippy, "
+                    "use `declare_clippy_lint!` instead"
+                )
+                sys.exit(42)
 
 
 def parse_configs(path):
@@ -103,9 +101,11 @@ def parse_configs(path):
 
 def parse_all(path="clippy_lints/src"):
     lints = []
-    for filename in os.listdir(path):
-        if filename.endswith(".rs"):
-            parse_lints(lints, os.path.join(path, filename))
+    for root, dirs, files in os.walk(path):
+        for fn in files:
+            if fn.endswith('.rs'):
+                parse_lints(lints, os.path.join(root, fn))
+
     log.info("got %s lints", len(lints))
 
     configs = parse_configs(path)
index 70d49f940eebc3516b592957258f4bfd850ec300..1800fa05c9075a912d56a042fdab6b74a99e5f66 100755 (executable)
 #!/usr/bin/env python
-# Generate a Markdown table of all lints, and put it in README.md.
-# With -n option, only print the new table to stdout.
-# With -c option, print a warning and set exit status to 1 if a file would be
-# changed.
 
-import os
-import re
 import sys
 
-declare_deprecated_lint_re = re.compile(r'''
-    declare_deprecated_lint! \s* [{(] \s*
-    pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s*
-    " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})]
-''', re.VERBOSE | re.DOTALL)
-
-declare_clippy_lint_re = re.compile(r'''
-    declare_clippy_lint! \s* [{(] \s*
-    pub \s+ (?P<name>[A-Z_][A-Z_0-9]*) \s*,\s*
-    (?P<cat>[a-z_]+) \s*,\s*
-    " (?P<desc>(?:[^"\\]+|\\.)*) " \s* [})]
-''', re.VERBOSE | re.DOTALL)
-
-nl_escape_re = re.compile(r'\\\n\s*')
-
-docs_link = 'https://rust-lang-nursery.github.io/rust-clippy/master/index.html'
-
-
-def collect(deprecated_lints, clippy_lints, fn):
-    """Collect all lints from a file.
-
-    Adds entries to the lints list as `(module, name, level, desc)`.
-    """
-    with open(fn) as fp:
-        code = fp.read()
-
-    for match in declare_deprecated_lint_re.finditer(code):
-        # remove \-newline escapes from description string
-        desc = nl_escape_re.sub('', match.group('desc'))
-        deprecated_lints.append((os.path.splitext(os.path.basename(fn))[0],
-                                match.group('name').lower(),
-                                desc.replace('\\"', '"')))
-
-    for match in declare_clippy_lint_re.finditer(code):
-        # remove \-newline escapes from description string
-        desc = nl_escape_re.sub('', match.group('desc'))
-        cat = match.group('cat')
-        clippy_lints[cat].append((os.path.splitext(os.path.basename(fn))[0],
-                                  match.group('name').lower(),
-                                  "allow",
-                                  desc.replace('\\"', '"')))
-
-
-def gen_group(lints):
-    """Write lint group (list of all lints in the form module::NAME)."""
-    for (module, name, _, _) in sorted(lints):
-        yield '        %s::%s,\n' % (module, name.upper())
-
-
-def gen_mods(lints):
-    """Declare modules"""
-
-    for module in sorted(set(lint[0] for lint in lints)):
-        yield 'pub mod %s;\n' % module
-
-
-def gen_deprecated(lints):
-    """Declare deprecated lints"""
-
-    for lint in lints:
-        yield '    store.register_removed(\n'
-        yield '        "%s",\n' % lint[1]
-        yield '        "%s",\n' % lint[2]
-        yield '    );\n'
-
-
-def replace_region(fn, region_start, region_end, callback,
-                   replace_start=True, write_back=True):
-    """Replace a region in a file delimited by two lines matching regexes.
-
-    A callback is called to write the new region.  If `replace_start` is true,
-    the start delimiter line is replaced as well.  The end delimiter line is
-    never replaced.
-    """
-    # read current content
-    with open(fn) as fp:
-        lines = list(fp)
-
-    found = False
-
-    # replace old region with new region
-    new_lines = []
-    in_old_region = False
-    for line in lines:
-        if in_old_region:
-            if re.search(region_end, line):
-                in_old_region = False
-                new_lines.extend(callback())
-                new_lines.append(line)
-        elif re.search(region_start, line):
-            if not replace_start:
-                new_lines.append(line)
-            # old region starts here
-            in_old_region = True
-            found = True
-        else:
-            new_lines.append(line)
-
-    if not found:
-        print "regex " + region_start + " not found"
-
-    # write back to file
-    if write_back:
-        with open(fn, 'w') as fp:
-            fp.writelines(new_lines)
-
-    # if something changed, return true
-    return lines != new_lines
-
-
-def main(print_only=False, check=False):
-    deprecated_lints = []
-    clippy_lints = {
-        "correctness": [],
-        "style": [],
-        "complexity": [],
-        "perf": [],
-        "restriction": [],
-        "pedantic": [],
-        "cargo": [],
-        "nursery": [],
-    }
-
-    # check directory
-    if not os.path.isfile('clippy_lints/src/lib.rs'):
-        print('Error: call this script from clippy checkout directory!')
-        return
-
-    # collect all lints from source files
-    for fn in os.listdir('clippy_lints/src'):
-        if fn.endswith('.rs'):
-            collect(deprecated_lints, clippy_lints,
-                    os.path.join('clippy_lints', 'src', fn))
-
-    # determine version
-    with open('Cargo.toml') as fp:
-        for line in fp:
-            if line.startswith('version ='):
-                clippy_version = line.split()[2].strip('"')
-                break
-        else:
-            print('Error: version not found in Cargo.toml!')
-            return
-
-    all_lints = []
-    clippy_lint_groups = [
-        "correctness",
-        "style",
-        "complexity",
-        "perf",
-    ]
-    clippy_lint_list = []
-    for x in clippy_lint_groups:
-        clippy_lint_list += clippy_lints[x]
-    for _, value in clippy_lints.iteritems():
-        all_lints += value
-
-    if print_only:
-        print_clippy_lint_groups = [
-            "correctness",
-            "style",
-            "complexity",
-            "perf",
-            "pedantic",
-            "nursery",
-            "restriction"
-        ]
-        for group in print_clippy_lint_groups:
-            sys.stdout.write('\n## ' + group + '\n')
-            for (_, name, _, descr) in sorted(clippy_lints[group]):
-                sys.stdout.write('* [' + name + '](https://rust-lang-nursery.github.io/rust-clippy/master/index.html#' + name + ') (' + descr + ')\n')
-        return
-
-    # update the lint counter in README.md
-    changed = replace_region(
-        'README.md',
-        r'^\[There are \d+ lints included in this crate!\]\(https://rust-lang-nursery.github.io/rust-clippy/master/index.html\)$', "",
-        lambda: ['[There are %d lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)\n' %
-                 (len(all_lints))],
-        write_back=not check)
-
-    # update the links in the CHANGELOG
-    changed |= replace_region(
-        'CHANGELOG.md',
-        "<!-- begin autogenerated links to lint list -->",
-        "<!-- end autogenerated links to lint list -->",
-        lambda: ["[`{0}`]: {1}#{0}\n".format(l[1], docs_link) for l in
-                 sorted(all_lints + deprecated_lints,
-                        key=lambda l: l[1])],
-        replace_start=False, write_back=not check)
-
-    # update version of clippy_lints in Cargo.toml
-    changed |= replace_region(
-        'Cargo.toml', r'# begin automatic update', '# end automatic update',
-        lambda: ['clippy_lints = { version = "%s", path = "clippy_lints" }\n' %
-                 clippy_version],
-        replace_start=False, write_back=not check)
-
-    # update version of clippy_lints in Cargo.toml
-    changed |= replace_region(
-        'clippy_lints/Cargo.toml', r'# begin automatic update', '# end automatic update',
-        lambda: ['version = "%s"\n' % clippy_version],
-        replace_start=False, write_back=not check)
-
-    # update the `pub mod` list
-    changed |= replace_region(
-        'clippy_lints/src/lib.rs', r'begin lints modules', r'end lints modules',
-        lambda: gen_mods(all_lints),
-        replace_start=False, write_back=not check)
-
-    # same for "clippy_*" lint collections
-    changed |= replace_region(
-        'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy"', r'\]\);',
-        lambda: gen_group(clippy_lint_list),
-        replace_start=False, write_back=not check)
-
-    for key, value in clippy_lints.iteritems():
-        # same for "clippy_*" lint collections
-        changed |= replace_region(
-            'clippy_lints/src/lib.rs', r'reg.register_lint_group\("clippy_' + key + r'"', r'\]\);',
-            lambda: gen_group(value),
-            replace_start=False, write_back=not check)
-
-    # same for "deprecated" lint collection
-    changed |= replace_region(
-        'clippy_lints/src/lib.rs', r'let mut store', r'end deprecated lints',
-        lambda: gen_deprecated(deprecated_lints),
-        replace_start=False,
-        write_back=not check)
-
-    if check and changed:
-        print('Please run util/update_lints.py to regenerate lints lists.')
-        return 1
-
+def main():
+    print('Error: Please use `util/dev` to update lints')
+    return 1
 
 if __name__ == '__main__':
-    sys.exit(main(print_only='-n' in sys.argv, check='-c' in sys.argv))
+    sys.exit(main())