about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/clippy/.github/driver.sh6
-rw-r--r--src/tools/clippy/CHANGELOG.md10
-rw-r--r--src/tools/clippy/CONTRIBUTING.md7
-rw-r--r--src/tools/clippy/README.md15
-rw-r--r--src/tools/clippy/clippy_dev/src/ra_setup.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/arithmetic.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/bytecount.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/consts.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs304
-rw-r--r--src/tools/clippy/clippy_lints/src/default_trait_access.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/functions.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/get_last_with_len.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_some_result.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ok_or.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/map_identity.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/match_on_vec_items.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs303
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrow.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_once.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs5
-rw-r--r--src/tools/clippy/doc/adding_lints.md2
-rw-r--r--src/tools/clippy/src/lintlist/mod.rs56
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs14
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.rs16
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.stderr50
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.fixed23
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.rs23
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.stderr28
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6250.rs16
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6250.stderr27
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6251.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6251.stderr43
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr46
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.stderr12
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6255.rs15
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6255.stderr13
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6256.rs13
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6256.stderr18
-rw-r--r--src/tools/clippy/tests/ui/field_reassign_with_default.rs110
-rw-r--r--src/tools/clippy/tests/ui/field_reassign_with_default.stderr75
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next.rs3
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next.stderr17
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.fixed10
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.rs10
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/filter_methods.stderr8
-rw-r--r--src/tools/clippy/tests/ui/find_map.stderr4
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs13
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr16
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.fixed2
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.rs2
-rw-r--r--src/tools/clippy/tests/ui/integer_arithmetic.rs10
-rw-r--r--src/tools/clippy/tests/ui/integer_arithmetic.stderr92
-rw-r--r--src/tools/clippy/tests/ui/item_after_statement.rs5
-rw-r--r--src/tools/clippy/tests/ui/item_after_statement.stderr15
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.stderr8
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.fixed40
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.rs44
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.stderr41
-rw-r--r--src/tools/clippy/tests/ui/map_collect_result_unit.fixed16
-rw-r--r--src/tools/clippy/tests/ui/map_collect_result_unit.rs16
-rw-r--r--src/tools/clippy/tests/ui/map_collect_result_unit.stderr16
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.rs40
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.stderr99
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed54
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs58
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr22
-rw-r--r--src/tools/clippy/tests/ui/match_type_on_diag_item.stderr8
-rw-r--r--src/tools/clippy/tests/ui/methods.rs5
-rw-r--r--src/tools/clippy/tests/ui/methods.stderr33
-rw-r--r--src/tools/clippy/tests/ui/methods_fixable.fixed11
-rw-r--r--src/tools/clippy/tests/ui/methods_fixable.rs11
-rw-r--r--src/tools/clippy/tests/ui/methods_fixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed1
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs1
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr24
-rw-r--r--src/tools/clippy/tests/ui/option_map_or_none.stderr4
-rw-r--r--src/tools/clippy/tests/ui/ref_option_ref.rs47
-rw-r--r--src/tools/clippy/tests/ui/ref_option_ref.stderr70
-rw-r--r--src/tools/clippy/tests/ui/single_char_add_str.fixed45
-rw-r--r--src/tools/clippy/tests/ui/single_char_add_str.rs45
-rw-r--r--src/tools/clippy/tests/ui/single_char_add_str.stderr94
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed12
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs6
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr72
-rw-r--r--src/tools/clippy/tests/ui/single_char_push_str.fixed15
-rw-r--r--src/tools/clippy/tests/ui/single_char_push_str.rs15
-rw-r--r--src/tools/clippy/tests/ui/single_char_push_str.stderr34
-rw-r--r--src/tools/clippy/tests/ui/skip_while_next.stderr8
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.fixed21
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.rs21
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg.stderr23
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs22
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr15
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.fixed31
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.rs9
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.stderr68
150 files changed, 2839 insertions, 675 deletions
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index 321e00df153..6ff189fc859 100644
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -24,16 +24,16 @@ unset CARGO_MANIFEST_DIR
 # FIXME: 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/double_neg.rs 2>double_neg.stderr && exit 1
 sed -e "s,tests/ui,\$DIR," -e "/= help/d" double_neg.stderr >normalized.stderr
-diff normalized.stderr tests/ui/double_neg.stderr
+diff -u normalized.stderr tests/ui/double_neg.stderr
 
 # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
 SYSROOT=$(rustc --print sysroot)
-diff <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose)
+diff -u <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose)
 
 echo "fn main() {}" >target/driver_test.rs
 # we can't run 2 rustcs on the same file at the same time
 CLIPPY=$(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver ./target/driver_test.rs --rustc)
 RUSTC=$(rustc ./target/driver_test.rs)
-diff <($CLIPPY) <($RUSTC)
+diff -u <($CLIPPY) <($RUSTC)
 
 # TODO: CLIPPY_CONF_DIR / CARGO_MANIFEST_DIR
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 25f3b5da198..1b9b33803de 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -22,7 +22,7 @@ Current beta, release 2020-11-19
 * [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
 * [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
 * [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
-* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
+* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
 
 ### Moves and Deprecations
 
@@ -1665,6 +1665,7 @@ Released 2018-09-13
 [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
+[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 [`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
@@ -1713,6 +1714,7 @@ Released 2018-09-13
 [`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
 [`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
 [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
+[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
@@ -1731,6 +1733,7 @@ Released 2018-09-13
 [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
 [`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
+[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
 [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
@@ -1795,6 +1798,7 @@ Released 2018-09-13
 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
+[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
@@ -1802,6 +1806,7 @@ Released 2018-09-13
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
 [`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_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
 [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 [`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore
 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
@@ -1917,6 +1922,7 @@ Released 2018-09-13
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
+[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
@@ -1937,8 +1943,8 @@ Released 2018-09-13
 [`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_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
 [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
-[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str
 [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 6494695606c..a8e2123656e 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -63,9 +63,10 @@ To figure out how this syntax structure is encoded in the AST, it is recommended
 Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
 But we can make it nest-less by using [if_chain] macro, [like this][nest-less].
 
-[`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.
+[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`]
+first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
+Note that [`E-medium`] issues may require some knowledge of Clippy internals or some 
+debugging to find the actual problem behind the issue. 
 
 [`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a
 lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index e1b3c84d691..8a5975e1f97 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -167,18 +167,21 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints:
 
 *   `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc.
 
-Note: `deny` produces errors instead of warnings.
+Note: `allow` means to suppress the lint for your code. With `warn` the lint
+will only emit a warning, while with `deny` the lint will emit an error, when
+triggering for your code. An error causes clippy to exit with an error code, so
+is useful in scripts like CI/CD.
 
-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:
+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:
 
-To disable `lint_name`, run
+To allow `lint_name`, run
 
 ```terminal
 cargo clippy -- -A clippy::lint_name
 ```
 
-And to enable `lint_name`, run
+And to warn on `lint_name`, run
 
 ```terminal
 cargo clippy -- -W clippy::lint_name
@@ -190,7 +193,7 @@ can run Clippy with warnings for all lints enabled:
 cargo clippy -- -W clippy::pedantic
 ```
 
-If you care only about a single lint, you can allow all others and then explicitly reenable
+If you care only about a single lint, you can allow all others and then explicitly warn on
 the lint(s) you are interested in:
 ```terminal
 cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
diff --git a/src/tools/clippy/clippy_dev/src/ra_setup.rs b/src/tools/clippy/clippy_dev/src/ra_setup.rs
index c67efc10f15..9d9e836cc08 100644
--- a/src/tools/clippy/clippy_dev/src/ra_setup.rs
+++ b/src/tools/clippy/clippy_dev/src/ra_setup.rs
@@ -11,7 +11,7 @@ use std::path::PathBuf;
 // code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details
 
 pub fn run(rustc_path: Option<&str>) {
-    // we can unwrap here because the arg is required here
+    // we can unwrap here because the arg is required by clap
     let rustc_path = PathBuf::from(rustc_path.unwrap());
     assert!(rustc_path.is_dir(), "path is not a directory");
     let rustc_source_basedir = rustc_path.join("compiler");
@@ -49,6 +49,15 @@ fn inject_deps_into_manifest(
     cargo_toml: &str,
     lib_rs: &str,
 ) -> std::io::Result<()> {
+    // do not inject deps if we have aleady done so
+    if cargo_toml.contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") {
+        eprintln!(
+            "cargo dev ra-setup: warning: deps already found inside {}, doing nothing.",
+            manifest_path
+        );
+        return Ok(());
+    }
+
     let extern_crates = lib_rs
         .lines()
         // get the deps
diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs
index e84481f9b53..9861d8cfc4e 100644
--- a/src/tools/clippy/clippy_lints/src/arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs
@@ -88,9 +88,28 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic {
 
                 let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r));
                 if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
-                    span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                    self.expr_span = Some(expr.span);
-                } else if l_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {
+                    match op.node {
+                        hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind {
+                            hir::ExprKind::Lit(_lit) => (),
+                            hir::ExprKind::Unary(hir::UnOp::UnNeg, expr) => {
+                                if let hir::ExprKind::Lit(lit) = &expr.kind {
+                                    if let rustc_ast::ast::LitKind::Int(1, _) = lit.node {
+                                        span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                                        self.expr_span = Some(expr.span);
+                                    }
+                                }
+                            },
+                            _ => {
+                                span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                                self.expr_span = Some(expr.span);
+                            },
+                        },
+                        _ => {
+                            span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                            self.expr_span = Some(expr.span);
+                        },
+                    }
+                } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {
                     span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
                     self.expr_span = Some(expr.span);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index f6eadbdef0b..a004abb58b8 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -16,6 +16,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 use rustc_span::symbol::{Symbol, SymbolStr};
 use semver::Version;
 
@@ -286,14 +287,14 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                     },
                     _ => {},
                 }
-                if items.is_empty() || !attr.has_name(sym!(deprecated)) {
+                if items.is_empty() || !attr.has_name(sym::deprecated) {
                     return;
                 }
                 for item in items {
                     if_chain! {
                         if let NestedMetaItem::MetaItem(mi) = &item;
                         if let MetaItemKind::NameValue(lit) = &mi.kind;
-                        if mi.has_name(sym!(since));
+                        if mi.has_name(sym::since);
                         then {
                             check_semver(cx, item.span(), lit);
                         }
@@ -309,7 +310,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
         }
         match item.kind {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
-                let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym!(macro_use)));
+                let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym::macro_use));
 
                 for attr in item.attrs {
                     if in_external_macro(cx.sess(), attr.span) {
@@ -326,7 +327,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                                         match item.kind {
                                             ItemKind::Use(..) => {
                                                 if is_word(lint, sym!(unused_imports))
-                                                    || is_word(lint, sym!(deprecated))
+                                                    || is_word(lint, sym::deprecated)
                                                     || is_word(lint, sym!(unreachable_pub))
                                                     || is_word(lint, sym!(unused))
                                                     || extract_clippy_lint(lint)
@@ -411,8 +412,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMet
     let lint_store = cx.lints();
     for lint in items {
         if let Some(lint_name) = extract_clippy_lint(lint) {
-            if let CheckLintNameResult::Tool(Err((None, _))) =
-                lint_store.check_lint_name(&lint_name, Some(sym!(clippy)))
+            if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym::clippy))
             {
                 span_lint_and_then(
                     cx,
@@ -529,10 +529,10 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut
 
     for attr in attrs {
         if let Some(values) = attr.meta_item_list() {
-            if values.len() != 1 || !attr.has_name(sym!(inline)) {
+            if values.len() != 1 || !attr.has_name(sym::inline) {
                 continue;
             }
-            if is_word(&values[0], sym!(always)) {
+            if is_word(&values[0], sym::always) {
                 span_lint(
                     cx,
                     INLINE_ALWAYS,
@@ -623,12 +623,12 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
 fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
     if_chain! {
         // check cfg_attr
-        if attr.has_name(sym!(cfg_attr));
+        if attr.has_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.has_name(sym!(rustfmt));
+        if feature_item.has_name(sym::rustfmt);
         // check for `rustfmt_skip` and `rustfmt::skip`
         if let Some(skip_item) = &items[1].meta_item();
         if skip_item.has_name(sym!(rustfmt_skip)) ||
@@ -690,7 +690,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
     }
 
     if_chain! {
-        if attr.has_name(sym!(cfg));
+        if attr.has_name(sym::cfg);
         if let Some(list) = attr.meta_item_list();
         let mismatched = find_mismatched_target_os(&list);
         if !mismatched.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 280a2c7fe67..90bb0bd555f 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -11,6 +11,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for boolean expressions that can be written more
@@ -253,8 +254,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
         },
         ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => {
             let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
-            if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type))
-                && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type))
+            if !is_type_diagnostic_item(cx, type_of_receiver, sym::option_type)
+                && !is_type_diagnostic_item(cx, type_of_receiver, sym::result_type)
             {
                 return None;
             }
diff --git a/src/tools/clippy/clippy_lints/src/bytecount.rs b/src/tools/clippy/clippy_lints/src/bytecount.rs
index d7d02ebf985..38a0e27c4cf 100644
--- a/src/tools/clippy/clippy_lints/src/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/bytecount.rs
@@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 use rustc_span::Symbol;
 
 declare_clippy_lint! {
@@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
                         let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) =
                                 filter_args[0].kind {
                             let p = path.ident.name;
-                            if (p == sym!(iter) || p == sym!(iter_mut)) && args.len() == 1 {
+                            if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
                                 &args[0]
                             } else {
                                 &filter_args[0]
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 14ef8c319ef..b1bc2ec29e1 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
-use rustc_span::BytePos;
+use rustc_span::{sym, BytePos};
 
 use crate::utils::{is_type_diagnostic_item, snippet_opt, span_lint_and_help, LimitStack};
 
@@ -61,7 +61,7 @@ impl CognitiveComplexity {
         helper.visit_expr(expr);
         let CCHelper { cc, returns } = helper;
         let ret_ty = cx.typeck_results().node_type(expr.hir_id);
-        let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) {
+        let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::result_type) {
             returns
         } else {
             #[allow(clippy::integer_division)]
@@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
         hir_id: HirId,
     ) {
         let def_id = cx.tcx.hir().local_def_id(hir_id);
-        if !cx.tcx.has_attr(def_id.to_def_id(), sym!(test)) {
+        if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) {
             self.check(cx, kind, decl, body, span);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
index c8bbc9ce2b0..0035ded9356 100644
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ b/src/tools/clippy/clippy_lints/src/consts.rs
@@ -7,10 +7,10 @@ use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
 use rustc_lint::LateContext;
+use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt, ScalarInt};
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_middle::mir::interpret::Scalar;
 use rustc_span::symbol::Symbol;
 use std::cmp::Ordering::{self, Equal};
 use std::convert::TryInto;
@@ -501,7 +501,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 }
 
 pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
-    use rustc_middle::mir::interpret::{ConstValue};
+    use rustc_middle::mir::interpret::ConstValue;
     match result.val {
         ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
             match result.ty.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
new file mode 100644
index 00000000000..612c5355338
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -0,0 +1,304 @@
+use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet};
+use crate::utils::{span_lint_and_note, span_lint_and_sugg};
+use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir::def::Res;
+use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Adt, Ty};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+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()`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for immediate reassignment of fields initialized
+    /// with Default::default().
+    ///
+    /// **Why is this bad?**It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax).
+    ///
+    /// **Known problems:** Assignments to patterns that are of tuple type are not linted.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```
+    /// # #[derive(Default)]
+    /// # struct A { i: i32 }
+    /// let mut a: A = Default::default();
+    /// a.i = 42;
+    /// ```
+    /// Use instead:
+    /// ```
+    /// # #[derive(Default)]
+    /// # struct A { i: i32 }
+    /// let a = A {
+    ///     i: 42,
+    ///     .. Default::default()
+    /// };
+    /// ```
+    pub FIELD_REASSIGN_WITH_DEFAULT,
+    style,
+    "binding initialized with Default should have its fields set in the initializer"
+}
+
+#[derive(Default)]
+pub struct Default {
+    // Spans linted by `field_reassign_with_default`.
+    reassigned_linted: FxHashSet<Span>,
+}
+
+impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
+
+impl LateLintPass<'_> for Default {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            // Avoid cases already linted by `field_reassign_with_default`
+            if !self.reassigned_linted.contains(&expr.span);
+            if let ExprKind::Call(ref path, ..) = expr.kind;
+            if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
+            if let ExprKind::Path(ref qpath) = path.kind;
+            if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
+            if let QPath::Resolved(None, _path) = qpath;
+            then {
+                let expr_ty = cx.typeck_results().expr_ty(expr);
+                if let ty::Adt(def, ..) = expr_ty.kind() {
+                    // 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 replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
+                    span_lint_and_sugg(
+                        cx,
+                        DEFAULT_TRAIT_ACCESS,
+                        expr.span,
+                        &format!("calling `{}` is more clear than this expression", replacement),
+                        "try",
+                        replacement,
+                        Applicability::Unspecified, // First resolve the TODO above
+                    );
+                }
+            }
+        }
+    }
+
+    fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+        // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
+        // `default` method of the `Default` trait, and store statement index in current block being
+        // checked and the name of the bound variable
+        let binding_statements_using_default = enumerate_bindings_using_default(cx, block);
+
+        // start from the `let mut _ = _::default();` and look at all the following
+        // statements, see if they re-assign the fields of the binding
+        for (stmt_idx, binding_name, binding_type, span) in binding_statements_using_default {
+            // the last statement of a block cannot trigger the lint
+            if stmt_idx == block.stmts.len() - 1 {
+                break;
+            }
+
+            // find all "later statement"'s where the fields of the binding set as
+            // Default::default() get reassigned, unless the reassignment refers to the original binding
+            let mut first_assign = None;
+            let mut assigned_fields = Vec::new();
+            let mut cancel_lint = false;
+            for consecutive_statement in &block.stmts[stmt_idx + 1..] {
+                // interrupt if the statement is a let binding (`Local`) that shadows the original
+                // binding
+                if stmt_shadows_binding(consecutive_statement, binding_name) {
+                    break;
+                }
+                // find out if and which field was set by this `consecutive_statement`
+                else if let Some((field_ident, assign_rhs)) =
+                    field_reassigned_by_stmt(consecutive_statement, binding_name)
+                {
+                    // interrupt and cancel lint if assign_rhs references the original binding
+                    if contains_name(binding_name, assign_rhs) {
+                        cancel_lint = true;
+                        break;
+                    }
+
+                    // if the field was previously assigned, replace the assignment, otherwise insert the assignment
+                    if let Some(prev) = assigned_fields
+                        .iter_mut()
+                        .find(|(field_name, _)| field_name == &field_ident.name)
+                    {
+                        *prev = (field_ident.name, assign_rhs);
+                    } else {
+                        assigned_fields.push((field_ident.name, assign_rhs));
+                    }
+
+                    // also set first instance of error for help message
+                    if first_assign.is_none() {
+                        first_assign = Some(consecutive_statement);
+                    }
+                }
+                // interrupt also if no field was assigned, since we only want to look at consecutive statements
+                else {
+                    break;
+                }
+            }
+
+            // if there are incorrectly assigned fields, do a span_lint_and_note to suggest
+            // construction using `Ty { fields, ..Default::default() }`
+            if !assigned_fields.is_empty() && !cancel_lint {
+                // take the original assignment as span
+                let stmt = &block.stmts[stmt_idx];
+
+                if let StmtKind::Local(preceding_local) = &stmt.kind {
+                    // filter out fields like `= Default::default()`, because the FRU already covers them
+                    let assigned_fields = assigned_fields
+                        .into_iter()
+                        .filter(|(_, rhs)| !is_expr_default(rhs, cx))
+                        .collect::<Vec<(Symbol, &Expr<'_>)>>();
+
+                    // if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion.
+                    let ext_with_default = !fields_of_type(binding_type)
+                        .iter()
+                        .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));
+
+                    let field_list = assigned_fields
+                        .into_iter()
+                        .map(|(field, rhs)| {
+                            // extract and store the assigned value for help message
+                            let value_snippet = snippet(cx, rhs.span, "..");
+                            format!("{}: {}", field, value_snippet)
+                        })
+                        .collect::<Vec<String>>()
+                        .join(", ");
+
+                    let sugg = if ext_with_default {
+                        if field_list.is_empty() {
+                            format!("{}::default()", binding_type)
+                        } else {
+                            format!("{} {{ {}, ..Default::default() }}", binding_type, field_list)
+                        }
+                    } else {
+                        format!("{} {{ {} }}", binding_type, field_list)
+                    };
+
+                    // span lint once per statement that binds default
+                    span_lint_and_note(
+                        cx,
+                        FIELD_REASSIGN_WITH_DEFAULT,
+                        first_assign.unwrap().span,
+                        "field assignment outside of initializer for an instance created with Default::default()",
+                        Some(preceding_local.span),
+                        &format!(
+                            "consider initializing the variable with `{}` and removing relevant reassignments",
+                            sugg
+                        ),
+                    );
+                    self.reassigned_linted.insert(span);
+                }
+            }
+        }
+    }
+}
+
+/// Checks if the given expression is the `default` method belonging to the `Default` trait.
+fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
+    if_chain! {
+        if let ExprKind::Call(ref fn_expr, _) = &expr.kind;
+        if let ExprKind::Path(qpath) = &fn_expr.kind;
+        if let Res::Def(_, def_id) = qpath_res(cx, qpath, fn_expr.hir_id);
+        then {
+            // right hand side of assignment is `Default::default`
+            match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
+        } else {
+            false
+        }
+    }
+}
+
+/// Returns the block indices, identifiers and types of bindings set as `Default::default()`, except
+/// for when the pattern type is a tuple.
+fn enumerate_bindings_using_default<'tcx>(
+    cx: &LateContext<'tcx>,
+    block: &Block<'tcx>,
+) -> Vec<(usize, Symbol, Ty<'tcx>, Span)> {
+    block
+        .stmts
+        .iter()
+        .enumerate()
+        .filter_map(|(idx, stmt)| {
+            if_chain! {
+                // only take `let ...` statements
+                if let StmtKind::Local(ref local) = stmt.kind;
+                // only take bindings to identifiers
+                if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
+                // that are not tuples
+                let ty = cx.typeck_results().pat_ty(local.pat);
+                if !matches!(ty.kind(), ty::Tuple(_));
+                // only when assigning `... = Default::default()`
+                if let Some(ref expr) = local.init;
+                if is_expr_default(expr, cx);
+                then {
+                    Some((idx, ident.name, ty, expr.span))
+                } else {
+                    None
+                }
+            }
+        })
+        .collect()
+}
+
+fn stmt_shadows_binding(this: &Stmt<'_>, shadowed: Symbol) -> bool {
+    if let StmtKind::Local(local) = &this.kind {
+        if let PatKind::Binding(_, _, ident, _) = local.pat.kind {
+            return ident.name == shadowed;
+        }
+    }
+    false
+}
+
+/// Returns the reassigned field and the assigning expression (right-hand side of assign).
+fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
+    if_chain! {
+        // only take assignments
+        if let StmtKind::Semi(ref later_expr) = this.kind;
+        if let ExprKind::Assign(ref assign_lhs, ref assign_rhs, _) = later_expr.kind;
+        // only take assignments to fields where the left-hand side field is a field of
+        // the same binding as the previous statement
+        if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind;
+        if let ExprKind::Path(ref qpath) = binding.kind;
+        if let QPath::Resolved(_, path) = qpath;
+        if let Some(second_binding_name) = path.segments.last();
+        if second_binding_name.ident.name == binding_name;
+        then {
+            Some((field_ident, assign_rhs))
+        } else {
+            None
+        }
+    }
+}
+
+/// Returns the vec of fields for a struct and an empty vec for non-struct ADTs.
+fn fields_of_type(ty: Ty<'_>) -> Vec<Ident> {
+    if let Adt(adt, _) = ty.kind() {
+        if adt.is_struct() {
+            let variant = &adt.non_enum_variant();
+            return variant.fields.iter().map(|f| f.ident).collect();
+        }
+    }
+    vec![]
+}
diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
deleted file mode 100644
index 3048436d9a7..00000000000
--- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-use crate::utils::{any_parent_is_automatically_derived, match_def_path, paths, span_lint_and_sugg};
-
-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()`"
-}
-
-declare_lint_pass!(DefaultTraitAccess => [DEFAULT_TRAIT_ACCESS]);
-
-impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::Call(ref path, ..) = expr.kind;
-            if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
-            if let ExprKind::Path(ref qpath) = path.kind;
-            if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
-            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
-            // Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
-            if let QPath::Resolved(None, _path) = qpath;
-            then {
-                let expr_ty = cx.typeck_results().expr_ty(expr);
-                if let ty::Adt(def, ..) = expr_ty.kind() {
-                    // 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 replacement = format!("{}::default()", cx.tcx.def_path_str(def.did));
-                    span_lint_and_sugg(
-                        cx,
-                        DEFAULT_TRAIT_ACCESS,
-                        expr.span,
-                        &format!("calling `{}` is more clear than this expression", replacement),
-                        "try",
-                        replacement,
-                        Applicability::Unspecified, // First resolve the TODO above
-                    );
-                }
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 07f604cf714..edecba57e44 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -15,7 +15,7 @@ use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span};
-use rustc_span::{FileName, Pos};
+use rustc_span::{sym, FileName, Pos};
 use std::io;
 use std::ops::Range;
 use url::Url;
@@ -237,7 +237,7 @@ fn lint_for_missing_headers<'tcx>(
         );
     }
     if !headers.errors {
-        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
+        if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
             span_lint(
                 cx,
                 MISSING_ERRORS_DOC,
@@ -255,7 +255,7 @@ fn lint_for_missing_headers<'tcx>(
                 if let ty::Opaque(_, subs) = ret_ty.kind();
                 if let Some(gen) = subs.types().next();
                 if let ty::Generator(_, subs, _) = gen.kind();
-                if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type));
+                if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::result_type);
                 then {
                     span_lint(
                         cx,
@@ -333,7 +333,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
             let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span);
             spans.extend_from_slice(&current_spans);
             doc.push_str(&comment);
-        } else if attr.has_name(sym!(doc)) {
+        } else if attr.has_name(sym::doc) {
             // ignore mix of sugared and non-sugared doc
             // don't trigger the safety or errors check
             return DocHeaders {
@@ -479,7 +479,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, span: Span) {
                     | ItemKind::ExternCrate(..)
                     | ItemKind::ForeignMod(..) => return false,
                     // We found a main function ...
-                    ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym!(main) => {
+                    ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym::main => {
                         let is_async = matches!(sig.header.asyncness, Async::Yes{..});
                         let returns_nothing = match &sig.decl.output {
                             FnRetTy::Default(..) => true,
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 0240e80d814..f8038d06e50 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -5,6 +5,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
@@ -33,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
         if_chain! {
             // match call to unwrap
             if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args, _) = expr.kind;
-            if unwrap_fun.ident.name == sym!(unwrap);
+            if unwrap_fun.ident.name == sym::unwrap;
             // match call to write_fmt
             if !unwrap_args.is_empty();
             if let ExprKind::MethodCall(ref write_fun, _, write_args, _) =
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index a9e05fddbe7..fe817fe94f2 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
@@ -95,8 +95,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
                 let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
-                if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
-                    || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
+                if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type)
+                    || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type)
                 {
                     self.result.push(expr.span);
                 }
@@ -113,7 +113,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
 
     for impl_item in impl_items {
         if_chain! {
-            if impl_item.ident.name == sym!(from);
+            if impl_item.ident.name == sym::from;
             if let ImplItemKind::Fn(_, body_id) =
                 cx.tcx.hir().impl_item(impl_item.id).kind;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 26da058598e..8e41e0e34da 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -10,6 +10,7 @@ use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, MatchSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for the use of `format!("string literal with no
@@ -91,7 +92,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: &
         if pats.len() == 1;
         then {
             let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs();
-            if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+            if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym::string_type) {
                 return None;
             }
             if let ExprKind::Lit(ref lit) = format_args.kind {
@@ -186,15 +187,15 @@ fn check_unformatted(expr: &Expr<'_>) -> bool {
         if exprs.len() == 1;
         // struct `core::fmt::rt::v1::Argument`
         if let ExprKind::Struct(_, ref fields, _) = exprs[0].kind;
-        if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym!(format));
+        if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
         // struct `core::fmt::rt::v1::FormatSpec`
         if let ExprKind::Struct(_, ref fields, _) = format_field.expr.kind;
-        if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym!(precision));
+        if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
         if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
-        if last_path_segment(precision_path).ident.name == sym!(Implied);
-        if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym!(width));
+        if last_path_segment(precision_path).ident.name == sym::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.kind;
-        if last_path_segment(width_qpath).ident.name == sym!(Implied);
+        if last_path_segment(width_qpath).ident.name == sym::Implied;
         then {
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs
index 9c0efef95de..8b58d1f2601 100644
--- a/src/tools/clippy/clippy_lints/src/functions.rs
+++ b/src/tools/clippy/clippy_lints/src/functions.rs
@@ -16,6 +16,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 use rustc_target::spec::abi::Abi;
 use rustc_typeck::hir_ty_to_ty;
 
@@ -473,7 +474,7 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span
         if !in_external_macro(cx.sess(), item_span);
         if let hir::FnRetTy::Return(ref ty) = decl.output;
         if let hir::TyKind::Path(ref qpath) = ty.kind;
-        if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym!(result_type));
+        if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym::result_type);
         if let Some(ref args) = last_path_segment(qpath).args;
         if let [_, hir::GenericArg::Type(ref err_ty)] = args.args;
         if let hir::TyKind::Tup(t) = err_ty.kind;
diff --git a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
index 48ebcf5ebcd..cdd8a42e7cd 100644
--- a/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/get_last_with_len.rs
@@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for using `x.get(x.len() - 1)` instead of
@@ -55,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for GetLastWithLen {
             // Argument 0 (the struct we're calling the method on) is a vector
             if let Some(struct_calling_on) = args.get(0);
             let struct_ty = cx.typeck_results().expr_ty(struct_calling_on);
-            if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type));
+            if is_type_diagnostic_item(cx, struct_ty, sym::vec_type);
 
             // Argument to "get" is a subtraction
             if let Some(get_index_arg) = args.get(1);
diff --git a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
index 28b20cdeac3..e0a1f4c5ca4 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_some_result.rs
@@ -4,6 +4,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:*** Checks for unnecessary `ok()` in if let.
@@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet {
             if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _)  = body[0].pat.kind; //get operation
             if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
-            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym!(result_type));
+            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type);
             if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
 
             then {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 0877b44d901..b723d06a688 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -2,6 +2,7 @@ use if_chain::if_chain;
 use rustc_hir::{ImplItem, ImplItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 use crate::utils::{
     get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help,
@@ -107,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             if decl.inputs.len() == 1;
 
             // Check if return type is String
-            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type));
+            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::string_type);
 
             // Filters instances of to_string which are required by a trait
             if trait_ref_of_method(cx, impl_item.hir_id).is_none();
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 4b605fdb366..d1c3fdc7146 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Symbol;
+use rustc_span::{sym, Symbol};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `#[inline]` on trait methods without bodies
@@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
 
 fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
     for attr in attrs {
-        if !attr.has_name(sym!(inline)) {
+        if !attr.has_name(sym::inline) {
             continue;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index c8576bcfcb4..8998fae09de 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -2,7 +2,8 @@
 
 use crate::utils::span_lint;
 use rustc_ast::ast::{Block, ItemKind, StmtKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -53,7 +54,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
 
 impl EarlyLintPass for ItemsAfterStatements {
     fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
-        if item.span.from_expansion() {
+        if in_external_macro(cx.sess(), item.span) {
             return;
         }
 
@@ -67,7 +68,7 @@ impl EarlyLintPass for ItemsAfterStatements {
         // lint on all further items
         for stmt in stmts {
             if let StmtKind::Item(ref it) = *stmt {
-                if it.span.from_expansion() {
+                if in_external_macro(cx.sess(), it.span) {
                     return;
                 }
                 if let ItemKind::MacroDef(..) = it.kind {
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index c9c4891bb08..8e2f03d6e4e 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -68,7 +68,44 @@ declare_clippy_lint! {
     "traits or impls with a public `len` method but no corresponding `is_empty` method"
 }
 
-declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY]);
+declare_clippy_lint! {
+    /// **What it does:** Checks for comparing to an empty slice such as "" or [],`
+    /// and suggests using `.is_empty()` where applicable.
+    ///
+    /// **Why is this bad?** Some structures can answer `.is_empty()` much faster
+    /// than checking for equality. 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 in some contexts.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```ignore
+    /// if s == "" {
+    ///     ..
+    /// }
+    ///
+    /// if arr == [] {
+    ///     ..
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```ignore
+    /// if s.is_empty() {
+    ///     ..
+    /// }
+    ///
+    /// if arr.is_empty() {
+    ///     ..
+    /// }
+    /// ```
+    pub COMPARISON_TO_EMPTY,
+    style,
+    "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead"
+}
+
+declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]);
 
 impl<'tcx> LateLintPass<'tcx> for LenZero {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@@ -221,6 +258,8 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
         }
 
         check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
+    } else {
+        check_empty_expr(cx, span, method, lit, op)
     }
 }
 
@@ -258,6 +297,42 @@ fn check_len(
     }
 }
 
+fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
+    if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            COMPARISON_TO_EMPTY,
+            span,
+            "comparison to empty slice",
+            &format!("using `{}is_empty` is clearer and more explicit", op),
+            format!(
+                "{}{}.is_empty()",
+                op,
+                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
+            ),
+            applicability,
+        );
+    }
+}
+
+fn is_empty_string(expr: &Expr<'_>) -> bool {
+    if let ExprKind::Lit(ref lit) = expr.kind {
+        if let LitKind::Str(lit, _) = lit.node {
+            let lit = lit.as_str();
+            return lit == "";
+        }
+    }
+    false
+}
+
+fn is_empty_array(expr: &Expr<'_>) -> bool {
+    if let ExprKind::Array(ref arr) = expr.kind {
+        return arr.is_empty();
+    }
+    false
+}
+
 /// Checks if this type has an `is_empty` method.
 fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index e97fa543a09..126852df502 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -176,7 +176,7 @@ mod copies;
 mod copy_iterator;
 mod create_dir;
 mod dbg_macro;
-mod default_trait_access;
+mod default;
 mod dereference;
 mod derive;
 mod disallowed_method;
@@ -234,6 +234,7 @@ mod macro_use;
 mod main_recursion;
 mod manual_async_fn;
 mod manual_non_exhaustive;
+mod manual_ok_or;
 mod manual_strip;
 mod manual_unwrap_or;
 mod map_clone;
@@ -294,6 +295,7 @@ mod redundant_closure_call;
 mod redundant_field_names;
 mod redundant_pub_crate;
 mod redundant_static_lifetimes;
+mod ref_option_ref;
 mod reference;
 mod regex;
 mod repeat_once;
@@ -537,7 +539,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &copy_iterator::COPY_ITERATOR,
         &create_dir::CREATE_DIR,
         &dbg_macro::DBG_MACRO,
-        &default_trait_access::DEFAULT_TRAIT_ACCESS,
+        &default::DEFAULT_TRAIT_ACCESS,
+        &default::FIELD_REASSIGN_WITH_DEFAULT,
         &dereference::EXPLICIT_DEREF_METHODS,
         &derive::DERIVE_HASH_XOR_EQ,
         &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
@@ -615,6 +618,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &large_const_arrays::LARGE_CONST_ARRAYS,
         &large_enum_variant::LARGE_ENUM_VARIANT,
         &large_stack_arrays::LARGE_STACK_ARRAYS,
+        &len_zero::COMPARISON_TO_EMPTY,
         &len_zero::LEN_WITHOUT_IS_EMPTY,
         &len_zero::LEN_ZERO,
         &let_if_seq::USELESS_LET_IF_SEQ,
@@ -649,6 +653,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &main_recursion::MAIN_RECURSION,
         &manual_async_fn::MANUAL_ASYNC_FN,
         &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
+        &manual_ok_or::MANUAL_OK_OR,
         &manual_strip::MANUAL_STRIP,
         &manual_unwrap_or::MANUAL_UNWRAP_OR,
         &map_clone::MAP_CLONE,
@@ -692,6 +697,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::FILTER_NEXT,
         &methods::FIND_MAP,
         &methods::FLAT_MAP_IDENTITY,
+        &methods::FROM_ITER_INSTEAD_OF_COLLECT,
         &methods::GET_UNWRAP,
         &methods::INEFFICIENT_TO_STRING,
         &methods::INTO_ITER_ON_REF,
@@ -702,6 +708,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::ITER_NTH_ZERO,
         &methods::ITER_SKIP_NEXT,
         &methods::MANUAL_SATURATING_ARITHMETIC,
+        &methods::MAP_COLLECT_RESULT_UNIT,
         &methods::MAP_FLATTEN,
         &methods::MAP_UNWRAP_OR,
         &methods::NEW_RET_NO_SELF,
@@ -712,8 +719,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::RESULT_MAP_OR_INTO_OPTION,
         &methods::SEARCH_IS_SOME,
         &methods::SHOULD_IMPLEMENT_TRAIT,
+        &methods::SINGLE_CHAR_ADD_STR,
         &methods::SINGLE_CHAR_PATTERN,
-        &methods::SINGLE_CHAR_PUSH_STR,
         &methods::SKIP_WHILE_NEXT,
         &methods::STRING_EXTEND_CHARS,
         &methods::SUSPICIOUS_MAP,
@@ -807,6 +814,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &redundant_field_names::REDUNDANT_FIELD_NAMES,
         &redundant_pub_crate::REDUNDANT_PUB_CRATE,
         &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
+        &ref_option_ref::REF_OPTION_REF,
         &reference::DEREF_ADDROF,
         &reference::REF_IN_DEREF,
         &regex::INVALID_REGEX,
@@ -1030,6 +1038,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &sess.target,
     );
     store.register_late_pass(move || box pass_by_ref_or_value);
+    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
     store.register_late_pass(|| box try_err::TryErr);
     store.register_late_pass(|| box use_self::UseSelf);
     store.register_late_pass(|| box bytecount::ByteCount);
@@ -1047,7 +1056,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
     store.register_late_pass(|| box unwrap::Unwrap);
     store.register_late_pass(|| box duration_subsec::DurationSubsec);
-    store.register_late_pass(|| box default_trait_access::DefaultTraitAccess);
     store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
     store.register_late_pass(|| box non_copy_const::NonCopyConst);
     store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
@@ -1098,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
     store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
     store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+    store.register_late_pass(|| box default::Default::default());
     store.register_late_pass(|| box unused_self::UnusedSelf);
     store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
     store.register_late_pass(|| box exit::Exit);
@@ -1146,6 +1155,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
     store.register_late_pass(|| box self_assignment::SelfAssignment);
     store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
+    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
     store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
     store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
     store.register_late_pass(|| box manual_strip::ManualStrip);
@@ -1210,7 +1220,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
         LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
         LintId::of(&copy_iterator::COPY_ITERATOR),
-        LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS),
+        LintId::of(&default::DEFAULT_TRAIT_ACCESS),
         LintId::of(&dereference::EXPLICIT_DEREF_METHODS),
         LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY),
         LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE),
@@ -1234,6 +1244,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
         LintId::of(&loops::EXPLICIT_ITER_LOOP),
         LintId::of(&macro_use::MACRO_USE_IMPORTS),
+        LintId::of(&manual_ok_or::MANUAL_OK_OR),
         LintId::of(&map_err_ignore::MAP_ERR_IGNORE),
         LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&matches::MATCH_BOOL),
@@ -1258,6 +1269,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
         LintId::of(&ranges::RANGE_MINUS_ONE),
         LintId::of(&ranges::RANGE_PLUS_ONE),
+        LintId::of(&ref_option_ref::REF_OPTION_REF),
         LintId::of(&shadow::SHADOW_UNRELATED),
         LintId::of(&strings::STRING_ADD_ASSIGN),
         LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
@@ -1319,6 +1331,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&comparison_chain::COMPARISON_CHAIN),
         LintId::of(&copies::IFS_SAME_COND),
         LintId::of(&copies::IF_SAME_THEN_ELSE),
+        LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
         LintId::of(&derive::DERIVE_HASH_XOR_EQ),
         LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD),
         LintId::of(&doc::MISSING_SAFETY_DOC),
@@ -1366,6 +1379,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&int_plus_one::INT_PLUS_ONE),
         LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS),
         LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
+        LintId::of(&len_zero::COMPARISON_TO_EMPTY),
         LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
         LintId::of(&len_zero::LEN_ZERO),
         LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
@@ -1419,6 +1433,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::EXPECT_FUN_CALL),
         LintId::of(&methods::FILTER_NEXT),
         LintId::of(&methods::FLAT_MAP_IDENTITY),
+        LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
         LintId::of(&methods::INTO_ITER_ON_REF),
         LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
         LintId::of(&methods::ITER_CLONED_COLLECT),
@@ -1427,6 +1442,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::ITER_NTH_ZERO),
         LintId::of(&methods::ITER_SKIP_NEXT),
         LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
         LintId::of(&methods::NEW_RET_NO_SELF),
         LintId::of(&methods::OK_EXPECT),
         LintId::of(&methods::OPTION_AS_REF_DEREF),
@@ -1435,8 +1451,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
         LintId::of(&methods::SEARCH_IS_SOME),
         LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
+        LintId::of(&methods::SINGLE_CHAR_ADD_STR),
         LintId::of(&methods::SINGLE_CHAR_PATTERN),
-        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
         LintId::of(&methods::SKIP_WHILE_NEXT),
         LintId::of(&methods::STRING_EXTEND_CHARS),
         LintId::of(&methods::SUSPICIOUS_MAP),
@@ -1577,6 +1593,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
         LintId::of(&collapsible_if::COLLAPSIBLE_IF),
         LintId::of(&comparison_chain::COMPARISON_CHAIN),
+        LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT),
         LintId::of(&doc::MISSING_SAFETY_DOC),
         LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
         LintId::of(&enum_variants::ENUM_VARIANT_NAMES),
@@ -1592,6 +1609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&functions::RESULT_UNIT_ERR),
         LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
         LintId::of(&inherent_to_string::INHERENT_TO_STRING),
+        LintId::of(&len_zero::COMPARISON_TO_EMPTY),
         LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
         LintId::of(&len_zero::LEN_ZERO),
         LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
@@ -1615,18 +1633,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
         LintId::of(&methods::CHARS_LAST_CMP),
         LintId::of(&methods::CHARS_NEXT_CMP),
+        LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
         LintId::of(&methods::INTO_ITER_ON_REF),
         LintId::of(&methods::ITER_CLONED_COLLECT),
         LintId::of(&methods::ITER_NEXT_SLICE),
         LintId::of(&methods::ITER_NTH_ZERO),
         LintId::of(&methods::ITER_SKIP_NEXT),
         LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
         LintId::of(&methods::NEW_RET_NO_SELF),
         LintId::of(&methods::OK_EXPECT),
         LintId::of(&methods::OPTION_MAP_OR_NONE),
         LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
         LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
-        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
+        LintId::of(&methods::SINGLE_CHAR_ADD_STR),
         LintId::of(&methods::STRING_EXTEND_CHARS),
         LintId::of(&methods::UNNECESSARY_FOLD),
         LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS),
@@ -1953,6 +1973,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
     ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
     ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
     ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
+    ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
 }
 
 // only exists to let the dogfood integration test works.
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index c8a5a9c9431..4d737b3f49b 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -16,7 +16,6 @@ use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Symbol};
-use std::iter::FromIterator;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for lifetime annotations which can be removed by
@@ -214,14 +213,15 @@ fn could_use_elision<'tcx>(
     }
 
     if allowed_lts
-        .intersection(&FxHashSet::from_iter(
-            input_visitor
+        .intersection(
+            &input_visitor
                 .nested_elision_site_lts
                 .iter()
                 .chain(output_visitor.nested_elision_site_lts.iter())
                 .cloned()
-                .filter(|v| matches!(v, RefLt::Named(_))),
-        ))
+                .filter(|v| matches!(v, RefLt::Named(_)))
+                .collect(),
+        )
         .next()
         .is_some()
     {
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 5d4d3dbcff4..32c2562ee95 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -619,9 +619,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
                 }
 
                 let lhs_constructor = last_path_segment(qpath);
-                if method_path.ident.name == sym!(next)
+                if method_path.ident.name == sym::next
                     && match_trait_method(cx, match_expr, &paths::ITERATOR)
-                    && lhs_constructor.ident.name == sym!(Some)
+                    && lhs_constructor.ident.name == sym::Some
                     && (pat_args.is_empty()
                         || !is_refutable(cx, &pat_args[0])
                             && !is_used_inside(cx, iter_expr, &arms[0].body)
@@ -985,13 +985,13 @@ fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
         _ => false,
     };
 
-    is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
+    is_slice || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
 }
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if_chain! {
         if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
-        if method.ident.name == sym!(clone);
+        if method.ident.name == sym::clone;
         if args.len() == 1;
         if let Some(arg) = args.get(0);
         then { arg } else { expr }
@@ -1355,7 +1355,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
             if let Some(self_expr) = args.get(0);
             if let Some(pushed_item) = args.get(1);
             // Check that the method being called is push() on a Vec
-            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type));
+            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::vec_type);
             if path.ident.name.as_str() == "push";
             then {
                 return Some((self_expr, pushed_item))
@@ -1736,7 +1736,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr:
 /// Checks for `for` loops over `Option`s and `Result`s.
 fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
     let ty = cx.typeck_results().expr_ty(arg);
-    if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
+    if is_type_diagnostic_item(cx, ty, sym::option_type) {
         span_lint_and_help(
             cx,
             FOR_LOOPS_OVER_FALLIBLES,
@@ -1753,7 +1753,7 @@ fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
                 snippet(cx, arg.span, "_")
             ),
         );
-    } else if is_type_diagnostic_item(cx, ty, sym!(result_type)) {
+    } else if is_type_diagnostic_item(cx, ty, sym::result_type) {
         span_lint_and_help(
             cx,
             FOR_LOOPS_OVER_FALLIBLES,
@@ -2186,8 +2186,8 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
         if_chain! {
             // a range index op
             if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind;
-            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 (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 }
         }
@@ -2333,7 +2333,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     // will allow further borrows afterwards
     let ty = cx.typeck_results().expr_ty(e);
     is_iterable_array(ty, cx) ||
-    is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
+    is_type_diagnostic_item(cx, ty, sym::vec_type) ||
     match_type(cx, ty, &paths::LINKED_LIST) ||
     is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) ||
     is_type_diagnostic_item(cx, ty, sym!(hashset_type)) ||
@@ -2890,7 +2890,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
         then {
             let ty = cx.typeck_results().node_type(ty.hir_id);
-            if is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
+            if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                 is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) ||
                 match_type(cx, ty, &paths::BTREEMAP) ||
                 is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 9c623821fdd..a1450b0d5fe 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -5,7 +5,7 @@ use rustc_attr as attr;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
@@ -83,9 +83,9 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
     }
 
     fn is_doc_hidden(attr: &Attribute) -> bool {
-        attr.has_name(sym!(doc))
+        attr.has_name(sym::doc)
             && match attr.meta_item_list() {
-                Some(l) => attr::list_contains_name(&l, sym!(hidden)),
+                Some(l) => attr::list_contains_name(&l, sym::hidden),
                 None => false,
             }
     }
@@ -102,7 +102,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
                 "this seems like a manual implementation of the non-exhaustive pattern",
                 |diag| {
                     if_chain! {
-                        if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive)));
+                        if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
                         let header_span = cx.sess.source_map().span_until_char(item.span, '{');
                         if let Some(snippet) = snippet_opt(cx, header_span);
                         then {
@@ -154,7 +154,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data:
                 "this seems like a manual implementation of the non-exhaustive pattern",
                 |diag| {
                     if_chain! {
-                        if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive)));
+                        if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
                         let header_span = find_header_span(cx, item, data);
                         if let Some(snippet) = snippet_opt(cx, header_span);
                         then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
new file mode 100644
index 00000000000..c99d2e35b94
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
@@ -0,0 +1,99 @@
+use crate::utils::{
+    indent_of, is_type_diagnostic_item, match_qpath, paths, reindent_multiline, snippet_opt, span_lint_and_sugg,
+};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{def, Expr, ExprKind, PatKind, QPath};
+use rustc_lint::LintContext;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Finds patterns that reimplement `Option::ok_or`.
+    ///
+    /// **Why is this bad?**
+    /// Concise code helps focusing on behavior instead of boilerplate.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Examples:**
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.map_or(Err("error"), |v| Ok(v));
+    ///
+    /// let foo: Option<i32> = None;
+    /// foo.map_or(Err("error"), |v| Ok(v));
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.ok_or("error");
+    /// ```
+    pub MANUAL_OK_OR,
+    pedantic,
+    "finds patterns that can be encoded more concisely with `Option::ok_or`"
+}
+
+declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
+
+impl LateLintPass<'_> for ManualOkOr {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
+        if in_external_macro(cx.sess(), scrutinee.span) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::MethodCall(method_segment, _, args, _) = scrutinee.kind;
+            if method_segment.ident.name == sym!(map_or);
+            if args.len() == 3;
+            let method_receiver = &args[0];
+            let ty = cx.typeck_results().expr_ty(method_receiver);
+            if is_type_diagnostic_item(cx, ty, sym!(option_type));
+            let or_expr = &args[1];
+            if is_ok_wrapping(cx, &args[2]);
+            if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
+            if match_qpath(err_path, &paths::RESULT_ERR);
+            if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span);
+            if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
+            if let Some(indent) = indent_of(cx, scrutinee.span);
+            then {
+                let reindented_err_arg_snippet =
+                    reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_OK_OR,
+                    scrutinee.span,
+                    "this pattern reimplements `Option::ok_or`",
+                    "replace with",
+                    format!(
+                        "{}.ok_or({})",
+                        method_receiver_snippet,
+                        reindented_err_arg_snippet
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
+fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
+    if let ExprKind::Path(ref qpath) = map_expr.kind {
+        if match_qpath(qpath, &paths::RESULT_OK) {
+            return true;
+        }
+    }
+    if_chain! {
+        if let ExprKind::Closure(_, _, body_id, ..) = map_expr.kind;
+        let body = cx.tcx.hir().body(body_id);
+        if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
+        if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
+        if match_qpath(ok_path, &paths::RESULT_OK);
+        if let ExprKind::Path(QPath::Resolved(_, ok_arg_path)) = ok_arg.kind;
+        if let def::Res::Local(ok_arg_path_id) = ok_arg_path.res;
+        then { param_id == ok_arg_path_id } else { false }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
index 22aa37e41fe..9e2c6c7f231 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
@@ -8,6 +8,7 @@ use rustc_lint::LintContext;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:**
@@ -97,9 +98,9 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if_chain! {
         if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
         let ty = cx.typeck_results().expr_ty(scrutinee);
-        if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym!(option_type)) {
+        if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym::option_type) {
             Some(Case::Option)
-        } else if utils::is_type_diagnostic_item(cx, ty, sym!(result_type)) {
+        } else if utils::is_type_diagnostic_item(cx, ty, sym::result_type) {
             Some(Case::Result)
         } else {
             None
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 6d1c2ffbfbd..034cd99a9be 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Ident;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
@@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
             if args.len() == 2;
             if method.ident.as_str() == "map";
             let ty = cx.typeck_results().expr_ty(&args[0]);
-            if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
+            if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR);
             if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
             let closure_body = cx.tcx.hir().body(body_id);
             let closure_expr = remove_blocks(&closure_body.value);
diff --git a/src/tools/clippy/clippy_lints/src/map_identity.rs b/src/tools/clippy/clippy_lints/src/map_identity.rs
index d4c2e66ff4b..6b782385a38 100644
--- a/src/tools/clippy/clippy_lints/src/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/map_identity.rs
@@ -7,6 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function.
@@ -65,8 +66,8 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a
         if args.len() == 2 && method.ident.as_str() == "map";
         let caller_ty = cx.typeck_results().expr_ty(&args[0]);
         if match_trait_method(cx, expr, &paths::ITERATOR)
-            || is_type_diagnostic_item(cx, caller_ty, sym!(result_type))
-            || is_type_diagnostic_item(cx, caller_ty, sym!(option_type));
+            || is_type_diagnostic_item(cx, caller_ty, sym::result_type)
+            || is_type_diagnostic_item(cx, caller_ty, sym::option_type);
         then {
             Some(args)
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 076ef235b8b..e50d11a4d71 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `option.map(f)` where f is a function
@@ -206,9 +207,9 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr
     let var_arg = &map_args[0];
 
     let (map_type, variant, lint) =
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(option_type)) {
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::option_type) {
             ("Option", "Some", OPTION_MAP_UNIT_FN)
-        } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(result_type)) {
+        } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::result_type) {
             ("Result", "Ok", RESULT_MAP_UNIT_FN)
         } else {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
index 331b6c6c34a..086dae9422f 100644
--- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
@@ -5,6 +5,7 @@ use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`.
@@ -90,7 +91,7 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti
 fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
     let ty = ty.peel_refs();
-    is_type_diagnostic_item(cx, ty, sym!(vec_type))
+    is_type_diagnostic_item(cx, ty, sym::vec_type)
 }
 
 fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 4bdfca1a292..c6dca54e250 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -22,7 +22,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty, TyS};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
-use rustc_span::Symbol;
+use rustc_span::{sym, Symbol};
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry;
 use std::collections::Bound;
@@ -662,7 +662,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
             }
         } else {
             // not a block, don't lint
-            return; 
+            return;
         };
 
         let ty = cx.typeck_results().expr_ty(ex);
@@ -840,7 +840,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms
 
 fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
     let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
-    if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
+    if is_type_diagnostic_item(cx, ex_ty, sym::result_type) {
         for arm in arms {
             if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
                 let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
@@ -1509,6 +1509,7 @@ mod redundant_pattern_match {
     use rustc_errors::Applicability;
     use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath};
     use rustc_lint::LateContext;
+    use rustc_span::sym;
 
     pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Match(op, arms, ref match_source) = &expr.kind {
@@ -1552,7 +1553,7 @@ mod redundant_pattern_match {
         if_chain! {
             if keyword == "while";
             if let ExprKind::MethodCall(method_path, _, _, _) = op.kind;
-            if method_path.ident.name == sym!(next);
+            if method_path.ident.name == sym::next;
             if match_trait_method(cx, op, &paths::ITERATOR);
             then {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index 5dae7efad97..c83b6f2c329 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -7,6 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
 
 /// Checks for the `INEFFICIENT_TO_STRING` lint
 pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) {
@@ -50,7 +51,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
         return true;
     }
 
-    if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+    if is_type_diagnostic_item(cx, ty, sym::string_type) {
         return true;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index d250bfd71e9..7186656f4e1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -32,8 +32,7 @@ use crate::utils::{
     is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath,
     match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty,
     single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint,
-    span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth,
-    SpanlessEq,
+    span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -1291,8 +1290,8 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Warns when using `push_str` with a single-character string literal,
-    /// and `push` with a `char` would work fine.
+    /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal
+    /// where `push`/`insert` with a `char` would work fine.
     ///
     /// **Why is this bad?** It's less clear that we are pushing a single character.
     ///
@@ -1301,16 +1300,18 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// let mut string = String::new();
+    /// string.insert_str(0, "R");
     /// string.push_str("R");
     /// ```
     /// Could be written as
     /// ```rust
     /// let mut string = String::new();
+    /// string.insert(0, 'R');
     /// string.push('R');
     /// ```
-    pub SINGLE_CHAR_PUSH_STR,
+    pub SINGLE_CHAR_ADD_STR,
     style,
-    "`push_str()` used with a single-character string literal as parameter"
+    "`push_str()` or `insert_str()` used with a single-character string literal as parameter"
 }
 
 declare_clippy_lint! {
@@ -1349,6 +1350,60 @@ declare_clippy_lint! {
     "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `_.map(_).collect::<Result<(),_>()`.
+    ///
+    /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// (0..3).try_for_each(|t| Err(t));
+    /// ```
+    pub MAP_COLLECT_RESULT_UNIT,
+    style,
+    "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator`
+    /// trait.
+    ///
+    /// **Why is this bad?** It is recommended style to use collect. See
+    /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// use std::iter::FromIterator;
+    ///
+    /// let five_fives = std::iter::repeat(5).take(5);
+    ///
+    /// let v = Vec::from_iter(five_fives);
+    ///
+    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let five_fives = std::iter::repeat(5).take(5);
+    ///
+    /// let v: Vec<i32> = five_fives.collect();
+    ///
+    /// assert_eq!(v, vec![5, 5, 5, 5, 5]);
+    /// ```
+    pub FROM_ITER_INSTEAD_OF_COLLECT,
+    style,
+    "use `.collect()` instead of `::from_iter()`"
+}
+
 declare_lint_pass!(Methods => [
     UNWRAP_USED,
     EXPECT_USED,
@@ -1370,7 +1425,7 @@ declare_lint_pass!(Methods => [
     INEFFICIENT_TO_STRING,
     NEW_RET_NO_SELF,
     SINGLE_CHAR_PATTERN,
-    SINGLE_CHAR_PUSH_STR,
+    SINGLE_CHAR_ADD_STR,
     SEARCH_IS_SOME,
     FILTER_NEXT,
     SKIP_WHILE_NEXT,
@@ -1398,6 +1453,8 @@ declare_lint_pass!(Methods => [
     FILETYPE_IS_FILE,
     OPTION_AS_REF_DEREF,
     UNNECESSARY_LAZY_EVALUATIONS,
+    MAP_COLLECT_RESULT_UNIT,
+    FROM_ITER_INSTEAD_OF_COLLECT,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -1479,10 +1536,18 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"),
             ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
             ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
+            ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]),
             _ => {},
         }
 
         match expr.kind {
+            hir::ExprKind::Call(ref func, ref args) => {
+                if let hir::ExprKind::Path(path) = &func.kind {
+                    if match_qpath(path, &["from_iter"]) {
+                        lint_from_iter(cx, expr, args);
+                    }
+                }
+            },
             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);
@@ -1499,6 +1564,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
                         lint_single_char_push_string(cx, expr, args);
+                    } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
+                        lint_single_char_insert_string(cx, expr, args);
                     }
                 }
 
@@ -1655,7 +1722,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, item.span);
-            if item.ident.name == sym!(new);
+            if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.hir_id);
             let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty();
@@ -1712,7 +1779,7 @@ fn lint_or_fun_call<'tcx>(
                     "try this",
                     format!(
                         "{}.unwrap_or_default()",
-                        snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
+                        snippet_with_applicability(cx, self_expr.span, "..", &mut applicability)
                     ),
                     applicability,
                 );
@@ -1745,7 +1812,7 @@ fn lint_or_fun_call<'tcx>(
                     _ => (),
                 }
 
-                if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
+                if is_type_diagnostic_item(cx, ty, sym::vec_type) {
                     return;
                 }
             }
@@ -1842,11 +1909,11 @@ fn lint_expect_fun_call(
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, 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))
+                        && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref))
                         && {
                             let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
                             let base_type = arg_type.peel_refs();
-                            *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type))
+                            *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type)
                         }
                     {
                         &call_args[0]
@@ -1864,7 +1931,7 @@ fn lint_expect_fun_call(
     // converted to string.
     fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
         let arg_ty = cx.typeck_results().expr_ty(arg);
-        if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) {
+        if is_type_diagnostic_item(cx, arg_ty, sym::string_type) {
             return false;
         }
         if let ty::Ref(_, ty, ..) = arg_ty.kind() {
@@ -1951,9 +2018,9 @@ fn lint_expect_fun_call(
     }
 
     let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
-    let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
+    let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) {
         "||"
-    } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
+    } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) {
         "|_|"
     } else {
         return;
@@ -2119,7 +2186,7 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::
             return;
         };
 
-        let snippet = snippet_with_macro_callsite(cx, arg.span, "_");
+        let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
 
         span_lint_and_sugg(
             cx,
@@ -2140,7 +2207,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
         let ref_str = if *self_ty.kind() == ty::Str {
             ""
-        } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) {
+        } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) {
             "&"
         } else {
             return;
@@ -2155,9 +2222,9 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
             "try this",
             format!(
                 "{}.push_str({}{})",
-                snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
+                snippet_with_applicability(cx, args[0].span, "..", &mut applicability),
                 ref_str,
-                snippet_with_applicability(cx, target.span, "_", &mut applicability)
+                snippet_with_applicability(cx, target.span, "..", &mut applicability)
             ),
             applicability,
         );
@@ -2166,14 +2233,14 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E
 
 fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs();
-    if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) {
+    if is_type_diagnostic_item(cx, obj_ty, sym::string_type) {
         lint_string_extend(cx, expr, args);
     }
 }
 
 fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
     if_chain! {
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym!(vec_type));
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type);
         if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0]));
         if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
 
@@ -2326,7 +2393,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
                 );
             }
         }
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type))
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type)
         || matches!(
             &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
             ty::Array(_, _)
@@ -2359,7 +2426,7 @@ fn lint_iter_nth<'tcx>(
     let mut_str = if is_mut { "_mut" } else { "" };
     let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() {
         "slice"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vec_type)) {
+    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) {
         "Vec"
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) {
         "VecDeque"
@@ -2404,7 +2471,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args:
     let mut applicability = Applicability::MachineApplicable;
     let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
     let get_args_str = if get_args.len() > 1 {
-        snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability)
+        snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability)
     } else {
         return; // not linting on a .get().unwrap() chain or variant
     };
@@ -2412,7 +2479,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args:
     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 is_type_diagnostic_item(cx, expr_ty, sym!(vec_type)) {
+    } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) {
         needs_ref = get_args_str.parse::<usize>().is_ok();
         "Vec"
     } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) {
@@ -2464,7 +2531,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args:
         format!(
             "{}{}[{}]",
             borrow_str,
-            snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability),
+            snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability),
             get_args_str
         ),
         applicability,
@@ -2480,7 +2547,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[
                 cx,
                 ITER_SKIP_NEXT,
                 expr.span.trim_start(caller.span).unwrap(),
-                "called `skip(x).next()` on an iterator",
+                "called `skip(..).next()` on an iterator",
                 "use `nth` instead",
                 hint,
                 Applicability::MachineApplicable,
@@ -2498,7 +2565,7 @@ fn derefs_to_slice<'tcx>(
         match ty.kind() {
             ty::Slice(_) => true,
             ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
-            ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)),
+            ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type),
             ty::Array(_, size) => size
                 .try_eval_usize(cx.tcx, cx.param_env)
                 .map_or(false, |size| size < 32),
@@ -2508,7 +2575,7 @@ fn derefs_to_slice<'tcx>(
     }
 
     if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind {
-        if path.ident.name == sym!(iter) && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
+        if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) {
             Some(&args[0])
         } else {
             None
@@ -2533,9 +2600,9 @@ fn derefs_to_slice<'tcx>(
 fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
     let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs();
 
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
+    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
         Some((UNWRAP_USED, "an Option", "None"))
-    } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
+    } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) {
         Some((UNWRAP_USED, "a Result", "Err"))
     } else {
         None
@@ -2585,7 +2652,7 @@ fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::E
 fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
     if_chain! {
         // lint if the caller of `ok()` is a `Result`
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym!(result_type));
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type);
         let result_type = cx.typeck_results().expr_ty(&ok_args[0]);
         if let Some(error_type) = get_error_type(cx, result_type);
         if has_debug_impl(error_type, cx);
@@ -2615,7 +2682,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
                     _ => map_closure_ty.fn_sig(cx.tcx),
                 };
                 let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output());
-                is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type))
+                is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type)
             },
             _ => false,
         };
@@ -2641,7 +2708,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
     }
 
     // lint if caller of `.map().flatten()` is an Option
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
         let func_snippet = snippet(cx, map_args[1].span, "..");
         let hint = format!(".and_then({})", func_snippet);
         span_lint_and_sugg(
@@ -2665,8 +2732,8 @@ fn lint_map_unwrap_or_else<'tcx>(
     unwrap_args: &'tcx [hir::Expr<'_>],
 ) -> bool {
     // lint if the caller of `map()` is an `Option`
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type);
 
     if is_option || is_result {
         // Don't make a suggestion that may fail to compile due to mutably borrowing
@@ -2683,11 +2750,11 @@ fn lint_map_unwrap_or_else<'tcx>(
 
         // lint message
         let msg = if is_option {
-            "called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling \
-            `map_or_else(g, f)` instead"
+            "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 \
-            `.map_or_else(g, f)` instead"
+            "called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling \
+            `.map_or_else(<g>, <f>)` instead"
         };
         // get snippets for args to map() and unwrap_or_else()
         let map_snippet = snippet(cx, map_args[1].span, "..");
@@ -2697,16 +2764,15 @@ fn lint_map_unwrap_or_else<'tcx>(
         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_lint_and_note(
+            let var_snippet = snippet(cx, map_args[0].span, "..");
+            span_lint_and_sugg(
                 cx,
                 MAP_UNWRAP_OR,
                 expr.span,
                 msg,
-                None,
-                &format!(
-                    "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`",
-                    map_snippet, unwrap_snippet,
-                ),
+                "try this",
+                format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet),
+                Applicability::MachineApplicable,
             );
             return true;
         } else if same_span && multiline {
@@ -2720,8 +2786,8 @@ fn lint_map_unwrap_or_else<'tcx>(
 
 /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
 fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type);
 
     // There are two variants of this `map_or` lint:
     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@@ -2753,8 +2819,8 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
         if is_option {
             let self_snippet = snippet(cx, map_or_args[0].span, "..");
             let func_snippet = snippet(cx, map_or_args[2].span, "..");
-            let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
-                       `and_then(f)` instead";
+            let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
+                       `and_then(..)` instead";
             (
                 OPTION_MAP_OR_NONE,
                 msg,
@@ -2792,18 +2858,20 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
 fn lint_filter_next<'tcx>(cx: &LateContext<'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 msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
+                   `.find(..)` instead.";
         let filter_snippet = snippet(cx, filter_args[1].span, "..");
         if filter_snippet.lines().count() <= 1 {
+            let iter_snippet = snippet(cx, filter_args[0].span, "..");
             // add note if not multi-line
-            span_lint_and_note(
+            span_lint_and_sugg(
                 cx,
                 FILTER_NEXT,
                 expr.span,
                 msg,
-                None,
-                &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet),
+                "try this",
+                format!("{}.find({})", iter_snippet, filter_snippet),
+                Applicability::MachineApplicable,
             );
         } else {
             span_lint(cx, FILTER_NEXT, expr.span, msg);
@@ -2823,9 +2891,9 @@ fn lint_skip_while_next<'tcx>(
             cx,
             SKIP_WHILE_NEXT,
             expr.span,
-            "called `skip_while(p).next()` on an `Iterator`",
+            "called `skip_while(<p>).next()` on an `Iterator`",
             None,
-            "this is more succinctly expressed by calling `.find(!p)` instead",
+            "this is more succinctly expressed by calling `.find(!<p>)` instead",
         );
     }
 }
@@ -2839,7 +2907,7 @@ fn lint_filter_map<'tcx>(
 ) {
     // 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`";
+        let msg = "called `filter(..).map(..)` on an `Iterator`";
         let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
     }
@@ -2848,17 +2916,19 @@ fn lint_filter_map<'tcx>(
 /// lint use of `filter_map().next()` for `Iterators`
 fn lint_filter_map_next<'tcx>(cx: &LateContext<'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 msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
+                   `.find_map(..)` instead.";
         let filter_snippet = snippet(cx, filter_args[1].span, "..");
         if filter_snippet.lines().count() <= 1 {
-            span_lint_and_note(
+            let iter_snippet = snippet(cx, filter_args[0].span, "..");
+            span_lint_and_sugg(
                 cx,
                 FILTER_MAP_NEXT,
                 expr.span,
                 msg,
-                None,
-                &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet),
+                "try this",
+                format!("{}.find_map({})", iter_snippet, filter_snippet),
+                Applicability::MachineApplicable,
             );
         } else {
             span_lint(cx, FILTER_MAP_NEXT, expr.span, msg);
@@ -2875,7 +2945,7 @@ fn lint_find_map<'tcx>(
 ) {
     // 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`";
+        let msg = "called `find(..).map(..)` on an `Iterator`";
         let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
         span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
     }
@@ -2890,7 +2960,7 @@ fn lint_filter_map_map<'tcx>(
 ) {
     // 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`";
+        let msg = "called `filter_map(..).map(..)` on an `Iterator`";
         let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
     }
@@ -2905,7 +2975,7 @@ fn lint_filter_flat_map<'tcx>(
 ) {
     // 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`";
+        let msg = "called `filter(..).flat_map(..)` on an `Iterator`";
         let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
                     and filtering by returning `iter::empty()`";
         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
@@ -2921,7 +2991,7 @@ fn lint_filter_map_flat_map<'tcx>(
 ) {
     // 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`";
+        let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`";
         let hint = "this is more succinctly expressed by calling `.flat_map(..)` \
                     and filtering by returning `iter::empty()`";
         span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
@@ -3075,7 +3145,7 @@ fn lint_chars_cmp(
         if arg_char.len() == 1;
         if let hir::ExprKind::Path(ref qpath) = fun.kind;
         if let Some(segment) = single_segment_path(qpath);
-        if segment.ident.name == sym!(Some);
+        if segment.ident.name == sym::Some;
         then {
             let mut applicability = Applicability::MachineApplicable;
             let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
@@ -3092,9 +3162,9 @@ fn lint_chars_cmp(
                 "like this",
                 format!("{}{}.{}({})",
                         if info.eq { "" } else { "!" },
-                        snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
+                        snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
                         suggest,
-                        snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)),
+                        snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
                 applicability,
             );
 
@@ -3141,7 +3211,7 @@ fn lint_chars_cmp_with_unwrap<'tcx>(
                 "like this",
                 format!("{}{}.{}('{}')",
                         if info.eq { "" } else { "!" },
-                        snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
+                        snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
                         suggest,
                         c),
                 applicability,
@@ -3177,7 +3247,7 @@ fn get_hint_if_single_char_arg(
         if let hir::ExprKind::Lit(lit) = &arg.kind;
         if let ast::LitKind::Str(r, style) = lit.node;
         let string = r.as_str();
-        if string.len() == 1;
+        if string.chars().count() == 1;
         then {
             let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
             let ch = if let ast::StrStyle::Raw(nhash) = style {
@@ -3216,11 +3286,12 @@ fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &h
 fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
     if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
-        let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
+        let base_string_snippet =
+            snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
         let sugg = format!("{}.push({})", base_string_snippet, extension_string);
         span_lint_and_sugg(
             cx,
-            SINGLE_CHAR_PUSH_STR,
+            SINGLE_CHAR_ADD_STR,
             expr.span,
             "calling `push_str()` using a single-character string literal",
             "consider using `push` with a character literal",
@@ -3230,6 +3301,26 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args
     }
 }
 
+/// lint for length-1 `str`s as argument for `insert_str`
+fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+    let mut applicability = Applicability::MachineApplicable;
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
+        let base_string_snippet =
+            snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
+        let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
+        let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_ADD_STR,
+            expr.span,
+            "calling `insert_str()` using a single-character string literal",
+            "consider using `insert` with a character literal",
+            sugg,
+            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"
@@ -3259,7 +3350,7 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re
                 expr.span,
                 &format!("this call to `{}` does nothing", call_name),
                 "try this",
-                snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(),
+                snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(),
                 applicability,
             );
         }
@@ -3350,7 +3441,7 @@ fn lint_option_as_ref_deref<'tcx>(
     let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
 
     let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
-    if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) {
+    if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
         return;
     }
 
@@ -3445,10 +3536,46 @@ fn lint_option_as_ref_deref<'tcx>(
     }
 }
 
+fn lint_map_collect(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    map_args: &[hir::Expr<'_>],
+    collect_args: &[hir::Expr<'_>],
+) {
+    if_chain! {
+        // called on Iterator
+        if let [map_expr] = collect_args;
+        if match_trait_method(cx, map_expr, &paths::ITERATOR);
+        // return of collect `Result<(),_>`
+        let collect_ret_ty = cx.typeck_results().expr_ty(expr);
+        if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type);
+        if let ty::Adt(_, substs) = collect_ret_ty.kind();
+        if let Some(result_t) = substs.types().next();
+        if result_t.is_unit();
+        // get parts for snippet
+        if let [iter, map_fn] = map_args;
+        then {
+            span_lint_and_sugg(
+                cx,
+                MAP_COLLECT_RESULT_UNIT,
+                expr.span,
+                "`.map().collect()` can be replaced with `.try_for_each()`",
+                "try this",
+                format!(
+                    "{}.try_for_each({})",
+                    snippet(cx, iter.span, ".."),
+                    snippet(cx, map_fn.span, "..")
+                ),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
 /// Given a `Result<T, E>` type, return its error type (`E`).
 fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
     match ty.kind() {
-        ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1),
+        ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1),
         _ => None,
     }
 }
@@ -3770,6 +3897,28 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir
     span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg);
 }
 
+fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+    let ty = cx.typeck_results().expr_ty(expr);
+    let arg_ty = cx.typeck_results().expr_ty(&args[0]);
+
+    let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap();
+    let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap();
+
+    if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) {
+        // `expr` implements `FromIterator` trait
+        let iter_expr = snippet(cx, args[0].span, "..");
+        span_lint_and_sugg(
+            cx,
+            FROM_ITER_INSTEAD_OF_COLLECT,
+            expr.span,
+            "usage of `FromIterator::from_iter`",
+            "use `.collect()` instead of `::from_iter()`",
+            format!("{}.collect()", iter_expr),
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
+
 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
     expected.constness == actual.constness
         && expected.unsafety == actual.unsafety
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 95fa28e1c0f..7763fd5f113 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -7,7 +7,7 @@ use rustc_hir::{self, HirId, Path};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::Symbol;
+use rustc_span::{sym, Symbol};
 
 use super::MAP_UNWRAP_OR;
 
@@ -20,7 +20,7 @@ pub(super) fn lint<'tcx>(
     map_span: Span,
 ) {
     // lint if the caller of `map()` is an `Option`
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) {
         if !is_copy(cx, cx.typeck_results().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
@@ -53,15 +53,15 @@ pub(super) fn lint<'tcx>(
         // 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 arg = if unwrap_snippet == "None" { "None" } else { "<a>" };
         let unwrap_snippet_none = unwrap_snippet == "None";
         let suggest = if unwrap_snippet_none {
-            "and_then(f)"
+            "and_then(<f>)"
         } else {
-            "map_or(a, f)"
+            "map_or(<a>, <f>)"
         };
         let msg = &format!(
-            "called `map(f).unwrap_or({})` on an `Option` value. \
+            "called `map(<f>).unwrap_or({})` on an `Option` value. \
             This can be done more directly by calling `{}` instead",
             arg, suggest
         );
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 08b3eab9b7c..cde89983a26 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -3,6 +3,7 @@ use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_span::sym;
 
 use super::UNNECESSARY_LAZY_EVALUATIONS;
 
@@ -14,8 +15,8 @@ pub(super) fn lint<'tcx>(
     args: &'tcx [hir::Expr<'_>],
     simplify_using: &str,
 ) {
-    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type));
-    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type));
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::option_type);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::result_type);
 
     if is_option || is_result {
         if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 909e79f661a..308e92057b7 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -7,6 +7,7 @@ use rustc_hir::{
     StmtKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::DesugaringKind;
@@ -271,13 +272,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
         k: FnKind<'tcx>,
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
-        _: Span,
+        span: Span,
         _: HirId,
     ) {
         if let FnKind::Closure(_) = k {
             // Does not apply to closures
             return;
         }
+        if in_external_macro(cx.tcx.sess, span) {
+            return;
+        }
         for arg in iter_input_pats(decl, body) {
             if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
                 span_lint(
@@ -293,13 +297,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if_chain! {
+            if !in_external_macro(cx.tcx.sess, stmt.span);
             if let StmtKind::Local(ref local) = stmt.kind;
             if let PatKind::Binding(an, .., name, None) = local.pat.kind;
             if let Some(ref init) = local.init;
             if !higher::is_from_for_desugar(local);
             then {
                 if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut {
-                    let sugg_init = if init.span.from_expansion() {
+                    // use the macro callsite when the init span (but not the whole local span)
+                    // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
+                    let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() {
                         Sugg::hir_with_macro_callsite(cx, init, "..")
                     } else {
                         Sugg::hir(cx, init, "..")
@@ -310,7 +317,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
                         ("", sugg_init.addr())
                     };
                     let tyopt = if let Some(ref ty) = local.ty {
-                        format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "_"))
+                        format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, ".."))
                     } else {
                         String::new()
                     };
@@ -326,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
                                 "try",
                                 format!(
                                     "let {name}{tyopt} = {initref};",
-                                    name=snippet(cx, name.span, "_"),
+                                    name=snippet(cx, name.span, ".."),
                                     tyopt=tyopt,
                                     initref=initref,
                                 ),
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 813f9c43948..009e3d8937e 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -14,6 +14,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Warns if there is missing doc for any documentable item
@@ -105,10 +106,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
         let doc_hidden = self.doc_hidden()
             || attrs.iter().any(|attr| {
-                attr.has_name(sym!(doc))
+                attr.has_name(sym::doc)
                     && match attr.meta_item_list() {
                         None => false,
-                        Some(l) => attr::list_contains_name(&l[..], sym!(hidden)),
+                        Some(l) => attr::list_contains_name(&l[..], sym::hidden),
                     }
             });
         self.doc_hidden_stack.push(doc_hidden);
@@ -128,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             hir::ItemKind::Enum(..) => "an enum",
             hir::ItemKind::Fn(..) => {
                 // ignore main()
-                if it.ident.name == sym!(main) {
+                if it.ident.name == sym::main {
                     let def_id = it.hir_id.owner;
                     let def_key = cx.tcx.hir().def_key(def_id);
                     if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 3eae45b2819..53abe6086ea 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -4,6 +4,7 @@ use rustc_hir as hir;
 use rustc_lint::{self, LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** it lints if an exported function, method, trait method with default impl,
@@ -57,7 +58,7 @@ declare_clippy_lint! {
 }
 
 fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
-    let has_inline = attrs.iter().any(|a| a.has_name(sym!(inline)));
+    let has_inline = attrs.iter().any(|a| a.has_name(sym::inline));
     if !has_inline {
         span_lint(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index b71d5496a37..405c21d608d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for address of operations (`&`) that are going to
@@ -112,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
     }
 
     fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if item.attrs.iter().any(|a| a.has_name(sym!(automatically_derived))) {
+        if item.attrs.iter().any(|a| a.has_name(sym::automatically_derived)) {
             debug_assert!(self.derived_item.is_none());
             self.derived_item = Some(item.hir_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 2423eb4e6e3..1d0e230c6a7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, TypeFoldable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::misc::can_type_implement_copy;
@@ -204,12 +204,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
 
                         let deref_span = spans_need_deref.get(&canonical_id);
                         if_chain! {
-                            if is_type_diagnostic_item(cx, ty, sym!(vec_type));
+                            if is_type_diagnostic_item(cx, ty, sym::vec_type);
                             if let Some(clone_spans) =
                                 get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
                             if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind;
                             if let Some(elem_ty) = path.segments.iter()
-                                .find(|seg| seg.ident.name == sym!(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),
@@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                             }
                         }
 
-                        if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+                        if is_type_diagnostic_item(cx, ty, sym::string_type) {
                             if let Some(clone_spans) =
                                 get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                                 diag.span_suggestion(
@@ -302,7 +302,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
 /// 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)]
+        [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
             .iter()
             .any(|&allow| attr.has_name(allow))
     })
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 28d1322e946..68fdd0eb269 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{Ty, TyS};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for types with a `fn new() -> Self` method and no
@@ -91,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                             // impl of `Default`
                             return;
                         }
-                        if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) {
+                        if sig.decl.inputs.is_empty() && name == sym::new && cx.access_levels.is_reachable(id) {
                             let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 603440c0f83..485888fa944 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -7,6 +7,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 use rustc_span::symbol::{Ident, Symbol};
 use std::cmp::Ordering;
 
@@ -384,7 +385,7 @@ impl EarlyLintPass for NonExpressiveNames {
 }
 
 fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
-    if !attrs.iter().any(|attr| attr.has_name(sym!(test))) {
+    if !attrs.iter().any(|attr| attr.has_name(sym::test)) {
         let mut visitor = SimilarNamesLocalVisitor {
             names: Vec::new(),
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index eb7624b25a3..681dbce9769 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -8,6 +8,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:**
@@ -66,7 +67,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
 fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
     if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind {
         path.ident.name.to_ident_string() == "ok"
-            && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type))
+            && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type)
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index 4077aba6ef1..72dfccc1089 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -5,7 +5,7 @@ use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result.
@@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {
         hir_id: hir::HirId,
     ) {
         if !matches!(fn_kind, FnKind::Closure(_))
-            && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type))
+            && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type)
         {
             lint_impl_body(cx, span, body);
         }
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 19d355e64ca..ceecc8dbc06 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -3,6 +3,7 @@ use if_chain::if_chain;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
@@ -39,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
             if trait_ref.path.res.def_id() == eq_trait;
             then {
                 for impl_item in impl_items {
-                    if impl_item.ident.name == sym!(ne) {
+                    if impl_item.ident.name == sym::ne {
                         span_lint_hir(
                             cx,
                             PARTIALEQ_NE_IMPL,
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 28816c3076d..030650c3256 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -10,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutabil
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use rustc_target::abi::LayoutOf;
 use rustc_target::spec::abi::Abi;
 use rustc_target::spec::Target;
@@ -230,8 +230,8 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
                 }
                 for a in attrs {
                     if let Some(meta_items) = a.meta_item_list() {
-                        if a.has_name(sym!(proc_macro_derive))
-                            || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always)))
+                        if a.has_name(sym::proc_macro_derive)
+                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                         {
                             return;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 6b1c848a946..dcb643a28ae 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::MultiSpan;
+use rustc_span::{sym, MultiSpan};
 use std::borrow::Cow;
 
 declare_clippy_lint! {
@@ -181,7 +181,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
         }
 
         if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
-            if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
+            if is_type_diagnostic_item(cx, ty, sym::vec_type) {
                 let mut ty_snippet = None;
                 if_chain! {
                     if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
@@ -225,7 +225,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
                         },
                     );
                 }
-            } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+            } else if is_type_diagnostic_item(cx, ty, sym::string_type) {
                 if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                     span_lint_and_then(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 0a2d1b5fbe6..e0996804a59 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -3,6 +3,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 use std::fmt;
 
 declare_clippy_lint! {
@@ -92,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>(
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
     if let ExprKind::MethodCall(ref path_segment, _, ref args, _) = expr.kind {
         if is_expr_ty_raw_ptr(cx, &args[0]) {
-            if path_segment.ident.name == sym!(offset) {
+            if path_segment.ident.name == sym::offset {
                 return Some((&args[0], &args[1], Method::Offset));
             }
             if path_segment.ident.name == sym!(wrapping_offset) {
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index dbc676ae224..d9b280b7a85 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -4,6 +4,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 use crate::utils::sugg::Sugg;
 use crate::utils::{
@@ -143,7 +144,7 @@ impl QuestionMark {
     fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
         let expr_ty = cx.typeck_results().expr_ty(expression);
 
-        is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
+        is_type_diagnostic_item(cx, expr_ty, sym::option_type)
     }
 
     fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index de54711d851..79e9a56af9a 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -7,6 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{Span, Spanned};
+use rustc_span::sym;
 use rustc_span::symbol::Ident;
 use std::cmp::Ordering;
 
@@ -304,7 +305,7 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args:
         if_chain! {
             // `.iter()` call
             if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = *iter;
-            if iter_path.ident.name == sym!(iter);
+            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(zip_arg);
             if is_integer_const(cx, start, 0);
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index ae3b0a03754..b4a9804fb25 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -17,6 +17,7 @@ use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
 use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
+use rustc_span::sym;
 use std::convert::TryFrom;
 use std::ops::ControlFlow;
 
@@ -115,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
             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)
-                    && is_type_diagnostic_item(cx, arg_ty, sym!(string_type)));
+                    && is_type_diagnostic_item(cx, arg_ty, sym::string_type));
 
             let from_deref = !from_borrow
                 && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF)
@@ -518,7 +519,10 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
                 self.possible_borrower.add(borrowed.local, lhs);
             },
             other => {
-                if ContainsRegion.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty).is_continue() {
+                if ContainsRegion
+                    .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
+                    .is_continue()
+                {
                     return;
                 }
                 rvalue_locals(other, |rhs| {
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
new file mode 100644
index 00000000000..a914a77d48b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -0,0 +1,66 @@
+use crate::utils::{last_path_segment, snippet, span_lint_and_sugg};
+use rustc_hir::{GenericArg, Mutability, Ty, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `&Option<&T>`.
+    ///
+    /// **Why is this bad?** Since `&` is Copy, it's useless to have a
+    /// reference on `Option<&T>`.
+    ///
+    /// **Known problems:** It may be irrevelent to use this lint on
+    /// public API code as it will make a breaking change to apply it.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// let x: &Option<&u32> = &Some(&0u32);
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let x: Option<&u32> = Some(&0u32);
+    /// ```
+    pub REF_OPTION_REF,
+    pedantic,
+    "use `Option<&T>` instead of `&Option<&T>`"
+}
+
+declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]);
+
+impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
+        if_chain! {
+            if let TyKind::Rptr(_, ref mut_ty) = ty.kind;
+            if mut_ty.mutbl == Mutability::Not;
+            if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
+            let last = last_path_segment(qpath);
+            if let Some(res) = last.res;
+            if let Some(def_id) = res.opt_def_id();
+
+            if cx.tcx.is_diagnostic_item(sym!(option_type), def_id);
+            if let Some(ref params) = last_path_segment(qpath).args ;
+            if !params.parenthesized;
+            if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg {
+                GenericArg::Type(inner_ty) => Some(inner_ty),
+                _ => None,
+            });
+            if let TyKind::Rptr(_, _) = inner_ty.kind;
+
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    REF_OPTION_REF,
+                    ty.span,
+                    "since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`",
+                    "try",
+                    format!("Option<{}>", &snippet(cx, inner_ty.span, "..")),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
index ae601353009..d34e744eb94 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs
@@ -5,6 +5,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types.
@@ -65,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
                         format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
                         Applicability::MachineApplicable,
                     );
-                } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
+                } else if is_type_diagnostic_item(cx, ty, sym::string_type) {
                     span_lint_and_sugg(
                         cx,
                         REPEAT_ONCE,
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index a6e4252a0c8..7f4913a02cb 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -9,6 +9,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then};
 
@@ -141,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
 }
 
 fn attr_is_cfg(attr: &Attribute) -> bool {
-    attr.meta_item_list().is_some() && attr.has_name(sym!(cfg))
+    attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
 }
 
 fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 3783bd78de2..0dd2da949c4 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -4,6 +4,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
+use rustc_span::sym;
 
 use if_chain::if_chain;
 
@@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd {
 }
 
 fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type))
+    is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::string_type)
 }
 
 fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 54b38d9f4ce..386987eb181 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -8,6 +8,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for manual swapping.
@@ -197,7 +198,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<
 
                 if matches!(ty.kind(), ty::Slice(_))
                     || matches!(ty.kind(), ty::Array(_, _))
-                    || is_type_diagnostic_item(cx, ty, sym!(vec_type))
+                    || is_type_diagnostic_item(cx, ty, sym::vec_type)
                     || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
                 {
                     return Slice::Swappable(lhs1, idx1, idx2);
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index 3e747ec4ad9..6f6b6999bf0 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usages of `Err(x)?`.
@@ -133,7 +134,7 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O
 fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     if_chain! {
         if let ty::Adt(_, subst) = ty.kind();
-        if is_type_diagnostic_item(cx, ty, sym!(result_type));
+        if is_type_diagnostic_item(cx, ty, sym::result_type);
         let err_ty = subst.type_at(1);
         then {
             Some(err_ty)
@@ -151,7 +152,7 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<
         let ready_ty = subst.type_at(0);
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym!(result_type), ready_def.did);
+        if cx.tcx.is_diagnostic_item(sym::result_type, ready_def.did);
         let err_ty = ready_subst.type_at(1);
 
         then {
@@ -170,11 +171,11 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) ->
         let ready_ty = subst.type_at(0);
 
         if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did);
+        if cx.tcx.is_diagnostic_item(sym::option_type, ready_def.did);
         let some_ty = ready_subst.type_at(0);
 
         if let ty::Adt(some_def, some_subst) = some_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym!(result_type), some_def.did);
+        if cx.tcx.is_diagnostic_item(sym::result_type, some_def.did);
         let err_ty = some_subst.type_at(1);
 
         then {
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index 6a33aaaaab2..c7d82da3b8b 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -10,9 +10,9 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{
-    BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
-    ImplItemKind, Item, ItemKind, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind,
-    TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
+    BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId,
+    ImplItem, ImplItemKind, Item, ItemKind, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt,
+    StmtKind, SyntheticTyParamKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
@@ -522,7 +522,7 @@ impl Types {
                             );
                             return; // don't recurse into the type
                         }
-                    } else if cx.tcx.is_diagnostic_item(sym!(vec_type), def_id) {
+                    } else if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) {
                         if_chain! {
                             // Get the _ part of Vec<_>
                             if let Some(ref last) = last_path_segment(qpath).args;
@@ -559,7 +559,7 @@ impl Types {
                                 return; // don't recurse into the type
                             }
                         }
-                    } else if cx.tcx.is_diagnostic_item(sym!(option_type), def_id) {
+                    } else if cx.tcx.is_diagnostic_item(sym::option_type, def_id) {
                         if match_type_parameter(cx, qpath, &paths::OPTION).is_some() {
                             span_lint(
                                 cx,
@@ -678,17 +678,30 @@ impl Types {
                             // details.
                             return;
                         }
+
+                        // When trait objects or opaque types have lifetime or auto-trait bounds,
+                        // we need to add parentheses to avoid a syntax error due to its ambiguity.
+                        // Originally reported as the issue #3128.
+                        let inner_snippet = snippet(cx, inner.span, "..");
+                        let suggestion = match &inner.kind {
+                            TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => {
+                                format!("&{}({})", ltopt, &inner_snippet)
+                            },
+                            TyKind::Path(qpath)
+                                if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
+                                    .map_or(false, |bounds| bounds.len() > 1) =>
+                            {
+                                format!("&{}({})", ltopt, &inner_snippet)
+                            },
+                            _ => format!("&{}{}", ltopt, &inner_snippet),
+                        };
                         span_lint_and_sugg(
                             cx,
                             BORROWED_BOX,
                             hir_ty.span,
                             "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
                             "try",
-                            format!(
-                                "&{}{}",
-                                ltopt,
-                                &snippet(cx, inner.span, "..")
-                            ),
+                            suggestion,
                             // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
                             // because the trait impls of it will break otherwise;
                             // and there may be other cases that result in invalid code.
@@ -721,6 +734,21 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool {
     false
 }
 
+fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
+    if_chain! {
+        if let Some(did) = qpath_res(cx, qpath, id).opt_def_id();
+        if let Some(node) = cx.tcx.hir().get_if_local(did);
+        if let Node::GenericParam(generic_param) = node;
+        if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
+        if synthetic == Some(SyntheticTyParamKind::ImplTrait);
+        then {
+            Some(generic_param.bounds)
+        } else {
+            None
+        }
+    }
+}
+
 declare_clippy_lint! {
     /// **What it does:** Checks for binding a unit value.
     ///
@@ -1582,7 +1610,7 @@ fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
         if names.is_empty() {
             return false;
         }
-        if names[0] == sym!(libc) || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) {
+        if names[0] == sym::libc || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) {
             return true;
         }
     }
@@ -2749,7 +2777,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
                 }
 
                 if match_path(ty_path, &paths::HASHMAP) {
-                    if method.ident.name == sym!(new) {
+                    if method.ident.name == sym::new {
                         self.suggestions
                             .insert(e.span, "HashMap::default()".to_string());
                     } else if method.ident.name == sym!(with_capacity) {
@@ -2762,7 +2790,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
                         );
                     }
                 } else if match_path(ty_path, &paths::HASHSET) {
-                    if method.ident.name == sym!(new) {
+                    if method.ident.name == sym::new {
                         self.suggestions
                             .insert(e.span, "HashSet::default()".to_string());
                     } else if method.ident.name == sym!(with_capacity) {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 1307237dbc7..0bccfc15678 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -6,6 +6,7 @@ use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegme
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, subst::GenericArgKind};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 use rustc_span::symbol::Ident;
 
 declare_clippy_lint! {
@@ -175,7 +176,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type));
+        if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type);
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 7548c6afa97..b1339c3d639 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -123,6 +123,17 @@ fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
         fn_source
             .rfind("->")
             .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
+                let mut rpos = rpos;
+                let chars: Vec<char> = fn_source.chars().collect();
+                while rpos > 1 {
+                    if let Some(c) = chars.get(rpos - 1) {
+                        if c.is_whitespace() {
+                            rpos -= 1;
+                            continue;
+                        }
+                    }
+                    break;
+                }
                 (
                     #[allow(clippy::cast_possible_truncation)]
                     ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index ea4b8172c9c..f4a77e54dd1 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -11,6 +11,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail.
@@ -92,11 +93,11 @@ fn collect_unwrap_info<'tcx>(
     invert: bool,
 ) -> Vec<UnwrapInfo<'tcx>> {
     fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
-        is_type_diagnostic_item(cx, ty, sym!(option_type)) && ["is_some", "is_none"].contains(&method_name)
+        is_type_diagnostic_item(cx, ty, sym::option_type) && ["is_some", "is_none"].contains(&method_name)
     }
 
     fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool {
-        is_type_diagnostic_item(cx, ty, sym!(result_type)) && ["is_ok", "is_err"].contains(&method_name)
+        is_type_diagnostic_item(cx, ty, sym::result_type) && ["is_ok", "is_err"].contains(&method_name)
     }
 
     if let ExprKind::Binary(op, left, right) = &expr.kind {
@@ -168,8 +169,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
             if_chain! {
                 if let ExprKind::MethodCall(ref method_name, _, ref args, _) = expr.kind;
                 if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].kind;
-                if [sym!(unwrap), sym!(unwrap_err)].contains(&method_name.ident.name);
-                let call_to_unwrap = method_name.ident.name == sym!(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.res == path.res);
                 // Span contexts should not differ with the conditional branch
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 0f8797243ec..fde31029330 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for functions of type Result that contain `expect()` or `unwrap()`
@@ -57,8 +57,8 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult {
             // first check if it's a method or function
             if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind;
             // checking if its return type is `result` or `option`
-            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type))
-                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type));
+            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::result_type)
+                || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::option_type);
             then {
                 lint_impl_body(cx, impl_item.span, impl_item);
             }
@@ -82,8 +82,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
             let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
-            if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
-                || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
+            if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type)
+                || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type)
             {
                 self.result.push(expr.span);
             }
@@ -92,8 +92,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
             let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
-            if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
-                || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
+            if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type)
+                || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type)
             {
                 self.result.push(expr.span);
             }
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 4e4a206a583..c6194b0c6de 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -9,6 +9,7 @@ use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, TyS};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls
@@ -106,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     if_chain! {
                         let a = cx.typeck_results().expr_ty(e);
                         let b = cx.typeck_results().expr_ty(&args[0]);
-                        if is_type_diagnostic_item(cx, a, sym!(result_type));
+                        if is_type_diagnostic_item(cx, a, sym::result_type);
                         if let ty::Adt(_, substs) = a.kind();
                         if let Some(a_type) = substs.types().next();
                         if TyS::same_type(a_type, b);
@@ -136,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     then {
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::TRY_FROM);
-                            if is_type_diagnostic_item(cx, a, sym!(result_type));
+                            if is_type_diagnostic_item(cx, a, sym::result_type);
                             if let ty::Adt(_, substs) = a.kind();
                             if let Some(a_type) = substs.types().next();
                             if TyS::same_type(a_type, b);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 6ca72d895c8..8b59a9541a7 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -225,7 +225,7 @@ declare_clippy_lint! {
     ///
     /// Good:
     /// ```rust,ignore
-    /// utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))
+    /// utils::is_type_diagnostic_item(cx, ty, sym::vec_type)
     /// ```
     pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
     internal,
@@ -724,7 +724,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
                     expr.span,
                     "usage of `utils::match_type()` on a type diagnostic item",
                     "try",
-                    format!("utils::is_type_diagnostic_item({}, {}, sym!({}))", cx_snippet, ty_snippet, item_name),
+                    format!("utils::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
                     Applicability::MaybeIncorrect,
                 );
             }
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 0a8a4a5f9ae..85e7f055e79 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -52,6 +52,7 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
+use rustc_span::sym as rustc_sym;
 use rustc_span::symbol::{self, kw, Symbol};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 use rustc_target::abi::Integer;
@@ -974,7 +975,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
 /// implementations have.
 pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(|attr| attr.has_name(sym!(automatically_derived)))
+    attrs.iter().any(|attr| attr.has_name(rustc_sym::automatically_derived))
 }
 
 /// Remove blocks around an expression.
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 736a531eda6..1ad8c602986 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -44,6 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"];
 pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
 pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
+pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
 pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
 pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 pub const HASH: [&str; 3] = ["core", "hash", "Hash"];
@@ -52,6 +53,7 @@ pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entr
 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 INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
 pub const INTO: [&str; 3] = ["core", "convert", "Into"];
 pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
 pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index d9d60fffcd7..ff414f748ef 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -10,8 +10,7 @@ use rustc_lexer::unescape::{self, EscapeError};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_parse::parser;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::Symbol;
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span, Symbol};
 
 declare_clippy_lint! {
     /// **What it does:** This lint warns when you use `println!("")` to
@@ -224,7 +223,7 @@ impl EarlyLintPass for Write {
                 .expect("path has at least one segment")
                 .ident
                 .name;
-            if trait_name == sym!(Debug) {
+            if trait_name == sym::Debug {
                 self.in_debug_impl = true;
             }
         }
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 2572833b8de..b1dacfc9c6d 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -311,7 +311,7 @@ Running our UI test should now produce output that contains the lint message.
 According to [the rustc-dev-guide], the text should be matter of fact and avoid
 capitalization and periods, unless multiple sentences are needed.
 When code or an identifier must appear in a message or label, it should be
-surrounded with single acute accents \`.
+surrounded with single grave accents \`.
 
 [check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
 [diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index c2e63ecb581..702f9d86de6 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -299,6 +299,13 @@ vec![
         module: "comparison_chain",
     },
     Lint {
+        name: "comparison_to_empty",
+        group: "style",
+        desc: "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead",
+        deprecation: None,
+        module: "len_zero",
+    },
+    Lint {
         name: "copy_iterator",
         group: "pedantic",
         desc: "implementing `Iterator` on a `Copy` type",
@@ -352,7 +359,7 @@ vec![
         group: "pedantic",
         desc: "checks for literal calls to `Default::default()`",
         deprecation: None,
-        module: "default_trait_access",
+        module: "default",
     },
     Lint {
         name: "deprecated_cfg_attr",
@@ -621,6 +628,13 @@ vec![
         module: "fallible_impl_from",
     },
     Lint {
+        name: "field_reassign_with_default",
+        group: "style",
+        desc: "binding initialized with Default should have its fields set in the initializer",
+        deprecation: None,
+        module: "default",
+    },
+    Lint {
         name: "filetype_is_file",
         group: "restriction",
         desc: "`FileType::is_file` is not recommended to test for readable file type",
@@ -747,6 +761,13 @@ vec![
         module: "drop_forget_ref",
     },
     Lint {
+        name: "from_iter_instead_of_collect",
+        group: "style",
+        desc: "use `.collect()` instead of `::from_iter()`",
+        deprecation: None,
+        module: "methods",
+    },
+    Lint {
         name: "future_not_send",
         group: "nursery",
         desc: "public Futures must be Send",
@@ -1174,6 +1195,13 @@ vec![
         module: "manual_non_exhaustive",
     },
     Lint {
+        name: "manual_ok_or",
+        group: "pedantic",
+        desc: "finds patterns that can be encoded more concisely with `Option::ok_or`",
+        deprecation: None,
+        module: "manual_ok_or",
+    },
+    Lint {
         name: "manual_range_contains",
         group: "style",
         desc: "manually reimplementing {`Range`, `RangeInclusive`}`::contains`",
@@ -1223,6 +1251,13 @@ vec![
         module: "map_clone",
     },
     Lint {
+        name: "map_collect_result_unit",
+        group: "style",
+        desc: "using `.map(_).collect::<Result<(),_>()`, which can be replaced with `try_for_each`",
+        deprecation: None,
+        module: "methods",
+    },
+    Lint {
         name: "map_entry",
         group: "perf",
         desc: "use of `contains_key` followed by `insert` on a `HashMap` or `BTreeMap`",
@@ -2014,6 +2049,13 @@ vec![
         module: "reference",
     },
     Lint {
+        name: "ref_option_ref",
+        group: "pedantic",
+        desc: "use `Option<&T>` instead of `&Option<&T>`",
+        deprecation: None,
+        module: "ref_option_ref",
+    },
+    Lint {
         name: "repeat_once",
         group: "complexity",
         desc: "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` ",
@@ -2133,16 +2175,16 @@ vec![
         module: "non_expressive_names",
     },
     Lint {
-        name: "single_char_pattern",
-        group: "perf",
-        desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`",
+        name: "single_char_add_str",
+        group: "style",
+        desc: "`push_str()` or `insert_str()` used with a single-character string literal as parameter",
         deprecation: None,
         module: "methods",
     },
     Lint {
-        name: "single_char_push_str",
-        group: "style",
-        desc: "`push_str()` used with a single-character string literal as parameter",
+        name: "single_char_pattern",
+        group: "perf",
+        desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`",
         deprecation: None,
         module: "methods",
     },
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index 0bbb9534928..93303865e17 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -56,3 +56,17 @@ macro_rules! option_env_unwrap_external {
         option_env!($env).expect($message)
     };
 }
+
+#[macro_export]
+macro_rules! ref_arg_binding {
+    () => {
+        let ref _y = 42;
+    };
+}
+
+#[macro_export]
+macro_rules! ref_arg_function {
+    () => {
+        fn fun_example(ref _x: usize) {}
+    };
+}
diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs
index 1901de46ca8..b606f773cfb 100644
--- a/src/tools/clippy/tests/ui/borrow_box.rs
+++ b/src/tools/clippy/tests/ui/borrow_box.rs
@@ -3,6 +3,8 @@
 #![allow(unused_variables)]
 #![allow(dead_code)]
 
+use std::fmt::Display;
+
 pub fn test1(foo: &mut Box<bool>) {
     // Although this function could be changed to "&mut bool",
     // avoiding the Box, mutable references to boxes are not
@@ -89,6 +91,20 @@ pub fn test13(boxed_slice: &mut Box<[i32]>) {
     *boxed_slice = data.into_boxed_slice();
 }
 
+// The suggestion should include proper parentheses to avoid a syntax error.
+pub fn test14(_display: &Box<dyn Display>) {}
+pub fn test15(_display: &Box<dyn Display + Send>) {}
+pub fn test16<'a>(_display: &'a Box<dyn Display + 'a>) {}
+
+pub fn test17(_display: &Box<impl Display>) {}
+pub fn test18(_display: &Box<impl Display + Send>) {}
+pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
+
+// This exists only to check what happens when parentheses are already present.
+// Even though the current implementation doesn't put extra parentheses,
+// it's fine that unnecessary parentheses appear in the future for some reason.
+pub fn test20(_display: &Box<(dyn Display + Send)>) {}
+
 fn main() {
     test1(&mut Box::new(false));
     test2();
diff --git a/src/tools/clippy/tests/ui/borrow_box.stderr b/src/tools/clippy/tests/ui/borrow_box.stderr
index b5db691f89f..3eac32815be 100644
--- a/src/tools/clippy/tests/ui/borrow_box.stderr
+++ b/src/tools/clippy/tests/ui/borrow_box.stderr
@@ -1,5 +1,5 @@
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> $DIR/borrow_box.rs:19:14
+  --> $DIR/borrow_box.rs:21:14
    |
 LL |     let foo: &Box<bool>;
    |              ^^^^^^^^^^ help: try: `&bool`
@@ -11,16 +11,58 @@ LL | #![deny(clippy::borrowed_box)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> $DIR/borrow_box.rs:23:10
+  --> $DIR/borrow_box.rs:25:10
    |
 LL |     foo: &'a Box<bool>,
    |          ^^^^^^^^^^^^^ help: try: `&'a bool`
 
 error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
-  --> $DIR/borrow_box.rs:27:17
+  --> $DIR/borrow_box.rs:29:17
    |
 LL |     fn test4(a: &Box<bool>);
    |                 ^^^^^^^^^^ help: try: `&bool`
 
-error: aborting due to 3 previous errors
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:95:25
+   |
+LL | pub fn test14(_display: &Box<dyn Display>) {}
+   |                         ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:96:25
+   |
+LL | pub fn test15(_display: &Box<dyn Display + Send>) {}
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:97:29
+   |
+LL | pub fn test16<'a>(_display: &'a Box<dyn Display + 'a>) {}
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:99:25
+   |
+LL | pub fn test17(_display: &Box<impl Display>) {}
+   |                         ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:100:25
+   |
+LL | pub fn test18(_display: &Box<impl Display + Send>) {}
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:101:29
+   |
+LL | pub fn test19<'a>(_display: &'a Box<impl Display + 'a>) {}
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)`
+
+error: you seem to be trying to use `&Box<T>`. Consider using just `&T`
+  --> $DIR/borrow_box.rs:106:25
+   |
+LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {}
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
new file mode 100644
index 00000000000..261024caca7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![warn(clippy::comparison_to_empty)]
+
+fn main() {
+    // Disallow comparisons to empty
+    let s = String::new();
+    let _ = s.is_empty();
+    let _ = !s.is_empty();
+
+    let v = vec![0];
+    let _ = v.is_empty();
+    let _ = !v.is_empty();
+
+    // Allow comparisons to non-empty
+    let s = String::new();
+    let _ = s == " ";
+    let _ = s != " ";
+
+    let v = vec![0];
+    let _ = v == [0];
+    let _ = v != [0];
+}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs
new file mode 100644
index 00000000000..98ddd974951
--- /dev/null
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs
@@ -0,0 +1,23 @@
+// run-rustfix
+
+#![warn(clippy::comparison_to_empty)]
+
+fn main() {
+    // Disallow comparisons to empty
+    let s = String::new();
+    let _ = s == "";
+    let _ = s != "";
+
+    let v = vec![0];
+    let _ = v == [];
+    let _ = v != [];
+
+    // Allow comparisons to non-empty
+    let s = String::new();
+    let _ = s == " ";
+    let _ = s != " ";
+
+    let v = vec![0];
+    let _ = v == [0];
+    let _ = v != [0];
+}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
new file mode 100644
index 00000000000..f69d6bd5255
--- /dev/null
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
@@ -0,0 +1,28 @@
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:8:13
+   |
+LL |     let _ = s == "";
+   |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+   |
+   = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
+
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:9:13
+   |
+LL |     let _ = s != "";
+   |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:12:13
+   |
+LL |     let _ = v == [];
+   |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:13:13
+   |
+LL |     let _ = v != [];
+   |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.rs b/src/tools/clippy/tests/ui/crashes/ice-6250.rs
new file mode 100644
index 00000000000..c33580ff6ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.rs
@@ -0,0 +1,16 @@
+// originally from glacier/fixed/77218.rs
+// ice while adjusting...
+
+pub struct Cache {
+    data: Vec<i32>,
+}
+
+pub fn list_data(cache: &Cache, key: usize) {
+    for reference in vec![1, 2, 3] {
+        if
+        /* let */
+        Some(reference) = cache.data.get(key) {
+            unimplemented!()
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
new file mode 100644
index 00000000000..8241dcd8feb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
@@ -0,0 +1,27 @@
+error[E0601]: `main` function not found in crate `ice_6250`
+  --> $DIR/ice-6250.rs:4:1
+   |
+LL | / pub struct Cache {
+LL | |     data: Vec<i32>,
+LL | | }
+LL | |
+...  |
+LL | |     }
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/ice-6250.rs`
+
+error[E0308]: mismatched types
+  --> $DIR/ice-6250.rs:12:9
+   |
+LL |         Some(reference) = cache.data.get(key) {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: you might have meant to use pattern matching
+   |
+LL |         let Some(reference) = cache.data.get(key) {
+   |         ^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0601.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.rs b/src/tools/clippy/tests/ui/crashes/ice-6251.rs
new file mode 100644
index 00000000000..6aa779aaeb3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6251.rs
@@ -0,0 +1,6 @@
+// originally from glacier/fixed/77329.rs
+// assertion failed: `(left == right) ; different DefIds
+
+fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
+    std::iter::empty()
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr
new file mode 100644
index 00000000000..9a7cf4b0919
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr
@@ -0,0 +1,43 @@
+error[E0601]: `main` function not found in crate `ice_6251`
+  --> $DIR/ice-6251.rs:4:1
+   |
+LL | / fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
+LL | |     std::iter::empty()
+LL | | }
+   | |_^ consider adding a `main` function to `$DIR/ice-6251.rs`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/ice-6251.rs:4:45
+   |
+LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
+   |                                             ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `[u8]`
+   = help: unsized fn params are gated as an unstable feature
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn bug<T>() -> impl Iterator<Item = [(); { |&x: [u8]| x }]> {
+   |                                             ^
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/ice-6251.rs:4:54
+   |
+LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
+   |                                                      ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `[u8]`
+   = note: the return type of a function must have a statically known size
+
+error[E0308]: mismatched types
+  --> $DIR/ice-6251.rs:4:44
+   |
+LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
+   |                                            ^^^^^^^^^^^ expected `usize`, found closure
+   |
+   = note: expected type `usize`
+           found closure `[closure@$DIR/ice-6251.rs:4:44: 4:55]`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0308, E0601.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.rs b/src/tools/clippy/tests/ui/crashes/ice-6252.rs
new file mode 100644
index 00000000000..2e3d9fd1e92
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.rs
@@ -0,0 +1,15 @@
+// originally from glacier fixed/77919.rs
+// encountered errors resolving bounds after type-checking
+
+trait TypeVal<T> {
+    const VAL: T;
+}
+struct Five;
+struct Multiply<N, M> {
+    _n: PhantomData,
+}
+impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+
+fn main() {
+    [1; <Multiply<Five, Five>>::VAL];
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
new file mode 100644
index 00000000000..440973e2439
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -0,0 +1,46 @@
+error[E0412]: cannot find type `PhantomData` in this scope
+  --> $DIR/ice-6252.rs:9:9
+   |
+LL |     _n: PhantomData,
+   |         ^^^^^^^^^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL | use std::marker::PhantomData;
+   |
+
+error[E0412]: cannot find type `VAL` in this scope
+  --> $DIR/ice-6252.rs:11:63
+   |
+LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   |          -                                                    ^^^ not found in this scope
+   |          |
+   |          help: you might be missing a type parameter: `, VAL`
+
+error[E0046]: not all trait items implemented, missing: `VAL`
+  --> $DIR/ice-6252.rs:11:1
+   |
+LL |     const VAL: T;
+   |     ------------- `VAL` from trait
+...
+LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+
+error: any use of this value will cause an error
+  --> $DIR/ice-6252.rs:5:5
+   |
+LL |     const VAL: T;
+   |     ^^^^^^^^^^^^^ no MIR body is available for DefId(0:5 ~ ice_6252[317d]::TypeVal::VAL)
+   |
+   = note: `#[deny(const_err)]` on by default
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ice-6252.rs:14:9
+   |
+LL |     [1; <Multiply<Five, Five>>::VAL];
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0046, E0080, E0412.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
new file mode 100644
index 00000000000..c19eca43884
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
@@ -0,0 +1,15 @@
+// originally from ./src/test/ui/pattern/usefulness/consts-opaque.rs
+// panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())',
+// compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5
+
+#[derive(PartialEq)]
+struct Foo(i32);
+const FOO_REF_REF: &&Foo = &&Foo(42);
+
+fn main() {
+    // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
+    match FOO_REF_REF {
+        FOO_REF_REF => {},
+        Foo(_) => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
new file mode 100644
index 00000000000..95ebf23d818
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
@@ -0,0 +1,12 @@
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/ice-6254.rs:12:9
+   |
+LL |         FOO_REF_REF => {},
+   |         ^^^^^^^^^^^
+   |
+   = note: `-D indirect-structural-match` implied by `-D warnings`
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6255.rs b/src/tools/clippy/tests/ui/crashes/ice-6255.rs
new file mode 100644
index 00000000000..bd4a81d98e2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6255.rs
@@ -0,0 +1,15 @@
+// originally from rustc ./src/test/ui/macros/issue-78325-inconsistent-resolution.rs
+// inconsistent resolution for a macro
+
+macro_rules! define_other_core {
+    ( ) => {
+        extern crate std as core;
+        //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+    };
+}
+
+fn main() {
+    core::panic!();
+}
+
+define_other_core!();
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6255.stderr b/src/tools/clippy/tests/ui/crashes/ice-6255.stderr
new file mode 100644
index 00000000000..d973ea1e23a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6255.stderr
@@ -0,0 +1,13 @@
+error: macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+  --> $DIR/ice-6255.rs:6:9
+   |
+LL |         extern crate std as core;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_other_core!();
+   | --------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6256.rs b/src/tools/clippy/tests/ui/crashes/ice-6256.rs
new file mode 100644
index 00000000000..6f60d45d68a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6256.rs
@@ -0,0 +1,13 @@
+// originally from rustc ./src/test/ui/regions/issue-78262.rs
+// ICE: to get the signature of a closure, use substs.as_closure().sig() not fn_sig()
+
+trait TT {}
+
+impl dyn TT {
+    fn func(&self) {}
+}
+
+fn main() {
+    let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types
+                                   //[nll]~^ ERROR: borrowed data escapes outside of closure
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6256.stderr b/src/tools/clippy/tests/ui/crashes/ice-6256.stderr
new file mode 100644
index 00000000000..0e8353a418a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-6256.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/ice-6256.rs:11:28
+   |
+LL |     let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types
+   |                            ^^^^ lifetime mismatch
+   |
+   = note: expected reference `&(dyn TT + 'static)`
+              found reference `&dyn TT`
+note: the anonymous lifetime #1 defined on the body at 11:13...
+  --> $DIR/ice-6256.rs:11:13
+   |
+LL |     let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
new file mode 100644
index 00000000000..79a30c22f95
--- /dev/null
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs
@@ -0,0 +1,110 @@
+#![warn(clippy::field_reassign_with_default)]
+
+#[derive(Default)]
+struct A {
+    i: i32,
+    j: i64,
+}
+
+struct B {
+    i: i32,
+    j: i64,
+}
+
+/// Implements .next() that returns a different number each time.
+struct SideEffect(i32);
+
+impl SideEffect {
+    fn new() -> SideEffect {
+        SideEffect(0)
+    }
+    fn next(&mut self) -> i32 {
+        self.0 += 1;
+        self.0
+    }
+}
+
+fn main() {
+    // wrong, produces first error in stderr
+    let mut a: A = Default::default();
+    a.i = 42;
+
+    // right
+    let mut a: A = Default::default();
+
+    // right
+    let a = A {
+        i: 42,
+        ..Default::default()
+    };
+
+    // right
+    let mut a: A = Default::default();
+    if a.i == 0 {
+        a.j = 12;
+    }
+
+    // right
+    let mut a: A = Default::default();
+    let b = 5;
+
+    // right
+    let mut b = 32;
+    let mut a: A = Default::default();
+    b = 2;
+
+    // right
+    let b: B = B { i: 42, j: 24 };
+
+    // right
+    let mut b: B = B { i: 42, j: 24 };
+    b.i = 52;
+
+    // right
+    let mut b = B { i: 15, j: 16 };
+    let mut a: A = Default::default();
+    b.i = 2;
+
+    // wrong, produces second error in stderr
+    let mut a: A = Default::default();
+    a.j = 43;
+    a.i = 42;
+
+    // wrong, produces third error in stderr
+    let mut a: A = Default::default();
+    a.i = 42;
+    a.j = 43;
+    a.j = 44;
+
+    // wrong, produces fourth error in stderr
+    let mut a = A::default();
+    a.i = 42;
+
+    // wrong, but does not produce an error in stderr, because we can't produce a correct kind of
+    // suggestion with current implementation
+    let mut c: (i32, i32) = Default::default();
+    c.0 = 42;
+    c.1 = 21;
+
+    // wrong, produces the fifth error in stderr
+    let mut a: A = Default::default();
+    a.i = Default::default();
+
+    // wrong, produces the sixth error in stderr
+    let mut a: A = Default::default();
+    a.i = Default::default();
+    a.j = 45;
+
+    // right, because an assignment refers to another field
+    let mut x = A::default();
+    x.i = 42;
+    x.j = 21 + x.i as i64;
+
+    // right, we bail out if there's a reassignment to the same variable, since there is a risk of
+    // side-effects affecting the outcome
+    let mut x = A::default();
+    let mut side_effect = SideEffect::new();
+    x.i = side_effect.next();
+    x.j = 2;
+    x.i = side_effect.next();
+}
diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
new file mode 100644
index 00000000000..c788ebae552
--- /dev/null
+++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr
@@ -0,0 +1,75 @@
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:30:5
+   |
+LL |     a.i = 42;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
+note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:29:5
+   |
+LL |     let mut a: A = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:70:5
+   |
+LL |     a.j = 43;
+   |     ^^^^^^^^^
+   |
+note: consider initializing the variable with `A { j: 43, i: 42 }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:69:5
+   |
+LL |     let mut a: A = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:75:5
+   |
+LL |     a.i = 42;
+   |     ^^^^^^^^^
+   |
+note: consider initializing the variable with `A { i: 42, j: 44 }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:74:5
+   |
+LL |     let mut a: A = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:81:5
+   |
+LL |     a.i = 42;
+   |     ^^^^^^^^^
+   |
+note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:80:5
+   |
+LL |     let mut a = A::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:91:5
+   |
+LL |     a.i = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider initializing the variable with `A::default()` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:90:5
+   |
+LL |     let mut a: A = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+  --> $DIR/field_reassign_with_default.rs:95:5
+   |
+LL |     a.i = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: consider initializing the variable with `A { j: 45, ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:94:5
+   |
+LL |     let mut a: A = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/filter_map_next.rs b/src/tools/clippy/tests/ui/filter_map_next.rs
index f5d051be198..dbeb2354309 100644
--- a/src/tools/clippy/tests/ui/filter_map_next.rs
+++ b/src/tools/clippy/tests/ui/filter_map_next.rs
@@ -3,9 +3,6 @@
 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()
diff --git a/src/tools/clippy/tests/ui/filter_map_next.stderr b/src/tools/clippy/tests/ui/filter_map_next.stderr
index d69ae212414..45427684d96 100644
--- a/src/tools/clippy/tests/ui/filter_map_next.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_next.stderr
@@ -1,14 +1,5 @@
-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
+error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead.
+  --> $DIR/filter_map_next.rs:7:26
    |
 LL |       let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
    |  __________________________^
@@ -19,6 +10,8 @@ LL | |             if x == 2 {
 LL | |         })
 LL | |         .next();
    | |_______________^
+   |
+   = note: `-D clippy::filter-map-next` implied by `-D warnings`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
new file mode 100644
index 00000000000..c3992d7e92c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#![warn(clippy::all, clippy::pedantic)]
+
+fn main() {
+    let a = ["1", "lol", "3", "NaN", "5"];
+
+    let element: Option<i32> = a.iter().find_map(|s| s.parse().ok());
+    assert_eq!(element, Some(1));
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
new file mode 100644
index 00000000000..447219a9683
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#![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));
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
new file mode 100644
index 00000000000..6c2530e0379
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
@@ -0,0 +1,10 @@
+error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead.
+  --> $DIR/filter_map_next_fixable.rs:8:32
+   |
+LL |     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
+   |
+   = note: `-D clippy::filter-map-next` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/filter_methods.stderr b/src/tools/clippy/tests/ui/filter_methods.stderr
index 84a957a374c..91718dd1175 100644
--- a/src/tools/clippy/tests/ui/filter_methods.stderr
+++ b/src/tools/clippy/tests/ui/filter_methods.stderr
@@ -1,4 +1,4 @@
-error: called `filter(p).map(q)` on an `Iterator`
+error: called `filter(..).map(..)` on an `Iterator`
   --> $DIR/filter_methods.rs:5:21
    |
 LL |     let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
@@ -7,7 +7,7 @@ LL |     let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x *
    = note: `-D clippy::filter-map` implied by `-D warnings`
    = help: this is more succinctly expressed by calling `.filter_map(..)` instead
 
-error: called `filter(p).flat_map(q)` on an `Iterator`
+error: called `filter(..).flat_map(..)` on an `Iterator`
   --> $DIR/filter_methods.rs:7:21
    |
 LL |       let _: Vec<_> = vec![5_i8; 6]
@@ -19,7 +19,7 @@ LL | |         .flat_map(|x| x.checked_mul(2))
    |
    = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
 
-error: called `filter_map(p).flat_map(q)` on an `Iterator`
+error: called `filter_map(..).flat_map(..)` on an `Iterator`
   --> $DIR/filter_methods.rs:13:21
    |
 LL |       let _: Vec<_> = vec![5_i8; 6]
@@ -31,7 +31,7 @@ LL | |         .flat_map(|x| x.checked_mul(2))
    |
    = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
 
-error: called `filter_map(p).map(q)` on an `Iterator`
+error: called `filter_map(..).map(..)` on an `Iterator`
   --> $DIR/filter_methods.rs:19:21
    |
 LL |       let _: Vec<_> = vec![5_i8; 6]
diff --git a/src/tools/clippy/tests/ui/find_map.stderr b/src/tools/clippy/tests/ui/find_map.stderr
index f279850fef8..aea3cc62afc 100644
--- a/src/tools/clippy/tests/ui/find_map.stderr
+++ b/src/tools/clippy/tests/ui/find_map.stderr
@@ -1,4 +1,4 @@
-error: called `find(p).map(q)` on an `Iterator`
+error: called `find(..).map(..)` on an `Iterator`
   --> $DIR/find_map.rs:20:26
    |
 LL |     let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
@@ -7,7 +7,7 @@ LL |     let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s
    = note: `-D clippy::find-map` implied by `-D warnings`
    = help: this is more succinctly expressed by calling `.find_map(..)` instead
 
-error: called `find(p).map(q)` on an `Iterator`
+error: called `find(..).map(..)` on an `Iterator`
   --> $DIR/find_map.rs:23:29
    |
 LL |       let _: Option<Flavor> = desserts_of_the_week
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
new file mode 100644
index 00000000000..045eb3133d3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
@@ -0,0 +1,13 @@
+#![warn(clippy::from_iter_instead_of_collect)]
+
+use std::collections::HashMap;
+use std::iter::FromIterator;
+
+fn main() {
+    let iter_expr = std::iter::repeat(5).take(5);
+    Vec::from_iter(iter_expr);
+
+    HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
+
+    Vec::from_iter(vec![42u32]);
+}
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
new file mode 100644
index 00000000000..46bdc2f4e19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
@@ -0,0 +1,16 @@
+error: usage of `FromIterator::from_iter`
+  --> $DIR/from_iter_instead_of_collect.rs:8:5
+   |
+LL |     Vec::from_iter(iter_expr);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()`
+   |
+   = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
+
+error: usage of `FromIterator::from_iter`
+  --> $DIR/from_iter_instead_of_collect.rs:10:5
+   |
+LL |     HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed
index 97e6b20f471..924c02a4054 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/get_unwrap.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused_mut)]
+#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
 #![deny(clippy::get_unwrap)]
 
 use std::collections::BTreeMap;
diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs
index 1c9a71c0969..c0c37bb7206 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.rs
+++ b/src/tools/clippy/tests/ui/get_unwrap.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(unused_mut)]
+#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
 #![deny(clippy::get_unwrap)]
 
 use std::collections::BTreeMap;
diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.rs b/src/tools/clippy/tests/ui/integer_arithmetic.rs
index 7b1b64f390a..b74c93dc4a6 100644
--- a/src/tools/clippy/tests/ui/integer_arithmetic.rs
+++ b/src/tools/clippy/tests/ui/integer_arithmetic.rs
@@ -11,6 +11,8 @@
 #[rustfmt::skip]
 fn main() {
     let mut i = 1i32;
+    let mut var1 = 0i32;
+    let mut var2 = -1i32;
     1 + i;
     i * 2;
     1 %
@@ -32,7 +34,15 @@ fn main() {
     i -= 1;
     i *= 2;
     i /= 2;
+    i /= 0;
+    i /= -1;
+    i /= var1;
+    i /= var2;
     i %= 2;
+    i %= 0;
+    i %= -1;
+    i %= var1;
+    i %= var2;
     i <<= 3;
     i >>= 2;
 
diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.stderr b/src/tools/clippy/tests/ui/integer_arithmetic.stderr
index 83e8a9cde3f..add3b6b90fa 100644
--- a/src/tools/clippy/tests/ui/integer_arithmetic.stderr
+++ b/src/tools/clippy/tests/ui/integer_arithmetic.stderr
@@ -1,5 +1,19 @@
+error: this operation will panic at runtime
+  --> $DIR/integer_arithmetic.rs:37:5
+   |
+LL |     i /= 0;
+   |     ^^^^^^ attempt to divide `_` by zero
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: this operation will panic at runtime
+  --> $DIR/integer_arithmetic.rs:42:5
+   |
+LL |     i %= 0;
+   |     ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero
+
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:14:5
+  --> $DIR/integer_arithmetic.rs:16:5
    |
 LL |     1 + i;
    |     ^^^^^
@@ -7,125 +21,149 @@ LL |     1 + i;
    = note: `-D clippy::integer-arithmetic` implied by `-D warnings`
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:15:5
+  --> $DIR/integer_arithmetic.rs:17:5
    |
 LL |     i * 2;
    |     ^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:16:5
+  --> $DIR/integer_arithmetic.rs:18:5
    |
 LL | /     1 %
 LL | |     i / 2; // no error, this is part of the expression in the preceding line
-   | |_________^
+   | |_____^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:18:5
+  --> $DIR/integer_arithmetic.rs:20:5
    |
 LL |     i - 2 + 2 - i;
    |     ^^^^^^^^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:19:5
+  --> $DIR/integer_arithmetic.rs:21:5
    |
 LL |     -i;
    |     ^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:20:5
+  --> $DIR/integer_arithmetic.rs:22:5
    |
 LL |     i >> 1;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:21:5
+  --> $DIR/integer_arithmetic.rs:23:5
    |
 LL |     i << 1;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:31:5
+  --> $DIR/integer_arithmetic.rs:33:5
    |
 LL |     i += 1;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:32:5
+  --> $DIR/integer_arithmetic.rs:34:5
    |
 LL |     i -= 1;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:33:5
+  --> $DIR/integer_arithmetic.rs:35:5
    |
 LL |     i *= 2;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:34:5
+  --> $DIR/integer_arithmetic.rs:38:11
    |
-LL |     i /= 2;
-   |     ^^^^^^
+LL |     i /= -1;
+   |           ^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:35:5
+  --> $DIR/integer_arithmetic.rs:39:5
    |
-LL |     i %= 2;
-   |     ^^^^^^
+LL |     i /= var1;
+   |     ^^^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:40:5
+   |
+LL |     i /= var2;
+   |     ^^^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:43:11
+   |
+LL |     i %= -1;
+   |           ^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:44:5
+   |
+LL |     i %= var1;
+   |     ^^^^^^^^^
+
+error: integer arithmetic detected
+  --> $DIR/integer_arithmetic.rs:45:5
+   |
+LL |     i %= var2;
+   |     ^^^^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:36:5
+  --> $DIR/integer_arithmetic.rs:46:5
    |
 LL |     i <<= 3;
    |     ^^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:37:5
+  --> $DIR/integer_arithmetic.rs:47:5
    |
 LL |     i >>= 2;
    |     ^^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:79:5
+  --> $DIR/integer_arithmetic.rs:89:5
    |
 LL |     3 + &1;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:80:5
+  --> $DIR/integer_arithmetic.rs:90:5
    |
 LL |     &3 + 1;
    |     ^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:81:5
+  --> $DIR/integer_arithmetic.rs:91:5
    |
 LL |     &3 + &1;
    |     ^^^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:86:5
+  --> $DIR/integer_arithmetic.rs:96:5
    |
 LL |     a + x
    |     ^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:90:5
+  --> $DIR/integer_arithmetic.rs:100:5
    |
 LL |     x + y
    |     ^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:94:5
+  --> $DIR/integer_arithmetic.rs:104:5
    |
 LL |     x + y
    |     ^^^^^
 
 error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:98:5
+  --> $DIR/integer_arithmetic.rs:108:5
    |
 LL |     (&x + &y)
    |     ^^^^^^^^^
 
-error: aborting due to 21 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/item_after_statement.rs b/src/tools/clippy/tests/ui/item_after_statement.rs
index c17a7cbc8d9..377e58e4417 100644
--- a/src/tools/clippy/tests/ui/item_after_statement.rs
+++ b/src/tools/clippy/tests/ui/item_after_statement.rs
@@ -28,7 +28,10 @@ fn mac() {
     // do not lint this, because it needs to be after `a`
     macro_rules! b {
         () => {{
-            a = 6
+            a = 6;
+            fn say_something() {
+                println!("something");
+            }
         }};
     }
     b!();
diff --git a/src/tools/clippy/tests/ui/item_after_statement.stderr b/src/tools/clippy/tests/ui/item_after_statement.stderr
index f8f010b5e5c..68a3c81b6a8 100644
--- a/src/tools/clippy/tests/ui/item_after_statement.stderr
+++ b/src/tools/clippy/tests/ui/item_after_statement.stderr
@@ -16,5 +16,18 @@ LL | |         println!("foo");
 LL | |     }
    | |_____^
 
-error: aborting due to 2 previous errors
+error: adding items after statements is confusing, since items exist from the start of the scope
+  --> $DIR/item_after_statement.rs:32:13
+   |
+LL | /             fn say_something() {
+LL | |                 println!("something");
+LL | |             }
+   | |_____________^
+...
+LL |       b!();
+   |       ----- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr
index feedc2f288a..486de718bb5 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.stderr
+++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr
@@ -1,4 +1,4 @@
-error: called `skip(x).next()` on an iterator
+error: called `skip(..).next()` on an iterator
   --> $DIR/iter_skip_next.rs:15:28
    |
 LL |     let _ = some_vec.iter().skip(42).next();
@@ -6,19 +6,19 @@ LL |     let _ = some_vec.iter().skip(42).next();
    |
    = note: `-D clippy::iter-skip-next` implied by `-D warnings`
 
-error: called `skip(x).next()` on an iterator
+error: called `skip(..).next()` on an iterator
   --> $DIR/iter_skip_next.rs:16:36
    |
 LL |     let _ = some_vec.iter().cycle().skip(42).next();
    |                                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)`
 
-error: called `skip(x).next()` on an iterator
+error: called `skip(..).next()` on an iterator
   --> $DIR/iter_skip_next.rs:17:20
    |
 LL |     let _ = (1..10).skip(10).next();
    |                    ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)`
 
-error: called `skip(x).next()` on an iterator
+error: called `skip(..).next()` on an iterator
   --> $DIR/iter_skip_next.rs:18:33
    |
 LL |     let _ = &some_vec[..].iter().skip(3).next();
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed
new file mode 100644
index 00000000000..b42e94bd727
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed
@@ -0,0 +1,40 @@
+// run-rustfix
+#![warn(clippy::manual_ok_or)]
+#![allow(clippy::blacklisted_name)]
+#![allow(clippy::redundant_closure)]
+#![allow(dead_code)]
+#![allow(unused_must_use)]
+
+fn main() {
+    // basic case
+    let foo: Option<i32> = None;
+    foo.ok_or("error");
+
+    // eta expansion case
+    foo.ok_or("error");
+
+    // turbo fish syntax
+    None::<i32>.ok_or("error");
+
+    // multiline case
+    #[rustfmt::skip]
+    foo.ok_or(&format!(
+        "{}{}{}{}{}{}{}",
+        "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer"));
+
+    // not applicable, closure isn't direct `Ok` wrapping
+    foo.map_or(Err("error"), |v| Ok(v + 1));
+
+    // not applicable, or side isn't `Result::Err`
+    foo.map_or(Ok::<i32, &str>(1), |v| Ok(v));
+
+    // not applicatble, expr is not a `Result` value
+    foo.map_or(42, |v| v);
+
+    // TODO patterns not covered yet
+    match foo {
+        Some(v) => Ok(v),
+        None => Err("error"),
+    };
+    foo.map_or_else(|| Err("error"), |v| Ok(v));
+}
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs
new file mode 100644
index 00000000000..e5a6056fbf5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_ok_or.rs
@@ -0,0 +1,44 @@
+// run-rustfix
+#![warn(clippy::manual_ok_or)]
+#![allow(clippy::blacklisted_name)]
+#![allow(clippy::redundant_closure)]
+#![allow(dead_code)]
+#![allow(unused_must_use)]
+
+fn main() {
+    // basic case
+    let foo: Option<i32> = None;
+    foo.map_or(Err("error"), |v| Ok(v));
+
+    // eta expansion case
+    foo.map_or(Err("error"), Ok);
+
+    // turbo fish syntax
+    None::<i32>.map_or(Err("error"), |v| Ok(v));
+
+    // multiline case
+    #[rustfmt::skip]
+    foo.map_or(Err::<i32, &str>(
+        &format!(
+            "{}{}{}{}{}{}{}",
+            "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")
+        ),
+        |v| Ok(v),
+    );
+
+    // not applicable, closure isn't direct `Ok` wrapping
+    foo.map_or(Err("error"), |v| Ok(v + 1));
+
+    // not applicable, or side isn't `Result::Err`
+    foo.map_or(Ok::<i32, &str>(1), |v| Ok(v));
+
+    // not applicatble, expr is not a `Result` value
+    foo.map_or(42, |v| v);
+
+    // TODO patterns not covered yet
+    match foo {
+        Some(v) => Ok(v),
+        None => Err("error"),
+    };
+    foo.map_or_else(|| Err("error"), |v| Ok(v));
+}
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.stderr b/src/tools/clippy/tests/ui/manual_ok_or.stderr
new file mode 100644
index 00000000000..8ea10ac5436
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_ok_or.stderr
@@ -0,0 +1,41 @@
+error: this pattern reimplements `Option::ok_or`
+  --> $DIR/manual_ok_or.rs:11:5
+   |
+LL |     foo.map_or(Err("error"), |v| Ok(v));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")`
+   |
+   = note: `-D clippy::manual-ok-or` implied by `-D warnings`
+
+error: this pattern reimplements `Option::ok_or`
+  --> $DIR/manual_ok_or.rs:14:5
+   |
+LL |     foo.map_or(Err("error"), Ok);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")`
+
+error: this pattern reimplements `Option::ok_or`
+  --> $DIR/manual_ok_or.rs:17:5
+   |
+LL |     None::<i32>.map_or(Err("error"), |v| Ok(v));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `None::<i32>.ok_or("error")`
+
+error: this pattern reimplements `Option::ok_or`
+  --> $DIR/manual_ok_or.rs:21:5
+   |
+LL | /     foo.map_or(Err::<i32, &str>(
+LL | |         &format!(
+LL | |             "{}{}{}{}{}{}{}",
+LL | |             "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")
+LL | |         ),
+LL | |         |v| Ok(v),
+LL | |     );
+   | |_____^
+   |
+help: replace with
+   |
+LL |     foo.ok_or(&format!(
+LL |         "{}{}{}{}{}{}{}",
+LL |         "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer"));
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.fixed b/src/tools/clippy/tests/ui/map_collect_result_unit.fixed
new file mode 100644
index 00000000000..e66c9cc2420
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_collect_result_unit.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+#![warn(clippy::map_collect_result_unit)]
+
+fn main() {
+    {
+        let _ = (0..3).try_for_each(|t| Err(t + 1));
+        let _: Result<(), _> = (0..3).try_for_each(|t| Err(t + 1));
+
+        let _ = (0..3).try_for_each(|t| Err(t + 1));
+    }
+}
+
+fn _ignore() {
+    let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<Vec<i32>, _>>();
+    let _ = (0..3).map(|t| Err(t + 1)).collect::<Vec<Result<(), _>>>();
+}
diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.rs b/src/tools/clippy/tests/ui/map_collect_result_unit.rs
new file mode 100644
index 00000000000..6f08f4c3c53
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_collect_result_unit.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+#![warn(clippy::map_collect_result_unit)]
+
+fn main() {
+    {
+        let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<(), _>>();
+        let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect();
+
+        let _ = (0..3).try_for_each(|t| Err(t + 1));
+    }
+}
+
+fn _ignore() {
+    let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<Vec<i32>, _>>();
+    let _ = (0..3).map(|t| Err(t + 1)).collect::<Vec<Result<(), _>>>();
+}
diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr
new file mode 100644
index 00000000000..8b06e13baa6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr
@@ -0,0 +1,16 @@
+error: `.map().collect()` can be replaced with `.try_for_each()`
+  --> $DIR/map_collect_result_unit.rs:6:17
+   |
+LL |         let _ = (0..3).map(|t| Err(t + 1)).collect::<Result<(), _>>();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))`
+   |
+   = note: `-D clippy::map-collect-result-unit` implied by `-D warnings`
+
+error: `.map().collect()` can be replaced with `.try_for_each()`
+  --> $DIR/map_collect_result_unit.rs:7:32
+   |
+LL |         let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect();
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.rs b/src/tools/clippy/tests/ui/map_unwrap_or.rs
index 585944032e7..87e16f5d09b 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.rs
@@ -1,4 +1,3 @@
-// FIXME: Add "run-rustfix" once it's supported for multipart suggestions
 // aux-build:option_helpers.rs
 
 #![warn(clippy::map_unwrap_or)]
@@ -47,10 +46,6 @@ fn option_methods() {
     let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
 
     // Check for `option.map(_).unwrap_or_else(_)` use.
-    // single line case
-    let _ = opt.map(|x| x + 1)
-        // Should lint even though this call is on a separate line.
-        .unwrap_or_else(|| 0);
     // Multi-line cases.
     let _ = opt.map(|x| {
         x + 1
@@ -60,37 +55,24 @@ fn option_methods() {
         .unwrap_or_else(||
             0
         );
-    // Macro case.
-    // Should not lint.
-    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
-
-    // Issue #4144
-    {
-        let mut frequencies = HashMap::new();
-        let word = "foo";
-
-        frequencies
-            .get_mut(word)
-            .map(|count| {
-                *count += 1;
-            })
-            .unwrap_or_else(|| {
-                frequencies.insert(word.to_owned(), 1);
-            });
-    }
 }
 
+#[rustfmt::skip]
 fn result_methods() {
     let res: Result<i32, ()> = Ok(1);
 
     // Check for `result.map(_).unwrap_or_else(_)` use.
-    // 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);
+    // 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
+    let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
index b62080a073f..96b9d6cc3c1 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
@@ -1,5 +1,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/map_unwrap_or.rs:17:13
+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/map_unwrap_or.rs:16:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -8,13 +8,13 @@ LL | |         .unwrap_or(0);
    | |_____________________^
    |
    = note: `-D clippy::map-unwrap-or` implied by `-D warnings`
-help: use `map_or(a, f)` instead
+help: use `map_or(<a>, <f>)` instead
    |
 LL |     let _ = opt.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/map_unwrap_or.rs:21:13
+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/map_unwrap_or.rs:20:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -23,7 +23,7 @@ LL | |     }
 LL | |     ).unwrap_or(0);
    | |__________________^
    |
-help: use `map_or(a, f)` instead
+help: use `map_or(<a>, <f>)` instead
    |
 LL |     let _ = opt.map_or(0, |x| {
 LL |         x + 1
@@ -31,8 +31,8 @@ LL |     }
 LL |     );
    |
 
-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/map_unwrap_or.rs:25:13
+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/map_unwrap_or.rs:24:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -41,26 +41,26 @@ LL | |             0
 LL | |         });
    | |__________^
    |
-help: use `map_or(a, f)` instead
+help: use `map_or(<a>, <f>)` instead
    |
 LL |     let _ = opt.map_or({
 LL |             0
 LL |         }, |x| 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/map_unwrap_or.rs:30:13
+error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
+  --> $DIR/map_unwrap_or.rs:29:13
    |
 LL |     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use `and_then(f)` instead
+help: use `and_then(<f>)` instead
    |
 LL |     let _ = opt.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/map_unwrap_or.rs:32:13
+error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
+  --> $DIR/map_unwrap_or.rs:31:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -69,7 +69,7 @@ LL | |     }
 LL | |     ).unwrap_or(None);
    | |_____________________^
    |
-help: use `and_then(f)` instead
+help: use `and_then(<f>)` instead
    |
 LL |     let _ = opt.and_then(|x| {
 LL |         Some(x + 1)
@@ -77,8 +77,8 @@ LL |     }
 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/map_unwrap_or.rs:36:13
+error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
+  --> $DIR/map_unwrap_or.rs:35:13
    |
 LL |       let _ = opt
    |  _____________^
@@ -86,35 +86,24 @@ LL | |         .map(|x| Some(x + 1))
 LL | |         .unwrap_or(None);
    | |________________________^
    |
-help: use `and_then(f)` instead
+help: use `and_then(<f>)` instead
    |
 LL |         .and_then(|x| Some(x + 1));
    |          ^^^^^^^^                --
 
-error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead
-  --> $DIR/map_unwrap_or.rs:47:13
+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/map_unwrap_or.rs:46:13
    |
 LL |     let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: use `map_or(a, f)` instead
+help: use `map_or(<a>, <f>)` instead
    |
 LL |     let _ = Some("prefix").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/map_unwrap_or.rs:51: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: 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/map_unwrap_or.rs:55:13
+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/map_unwrap_or.rs:50:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -123,8 +112,8 @@ LL | |     }
 LL | |     ).unwrap_or_else(|| 0);
    | |__________________________^
 
-error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead
-  --> $DIR/map_unwrap_or.rs:59:13
+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/map_unwrap_or.rs:54:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -133,29 +122,25 @@ LL | |             0
 LL | |         );
    | |_________^
 
-error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead
-  --> $DIR/map_unwrap_or.rs:88:13
+error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
+  --> $DIR/map_unwrap_or.rs:66: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: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)`
-
-error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead
-  --> $DIR/map_unwrap_or.rs:90: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 `map_or_else(|e| 0, |x| x + 1)`
+LL |       let _ = res.map(|x| {
+   |  _____________^
+LL | |         x + 1
+LL | |     }
+LL | |     ).unwrap_or_else(|_e| 0);
+   | |____________________________^
 
-error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead
-  --> $DIR/map_unwrap_or.rs:91:13
-   |
-LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
+  --> $DIR/map_unwrap_or.rs:70:13
    |
-   = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)`
+LL |       let _ = res.map(|x| x + 1)
+   |  _____________^
+LL | |         .unwrap_or_else(|_e| {
+LL | |             0
+LL | |         });
+   | |__________^
 
-error: aborting due to 13 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed
new file mode 100644
index 00000000000..bd5b4f7165a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed
@@ -0,0 +1,54 @@
+// run-rustfix
+// aux-build:option_helpers.rs
+
+#![warn(clippy::map_unwrap_or)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use std::collections::HashMap;
+
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or_else(_)` use.
+    // single line case
+    let _ = opt.map_or_else(|| 0, |x| x + 1);
+
+    // Macro case.
+    // Should not lint.
+    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
+
+    // Issue #4144
+    {
+        let mut frequencies = HashMap::new();
+        let word = "foo";
+
+        frequencies
+            .get_mut(word)
+            .map(|count| {
+                *count += 1;
+            })
+            .unwrap_or_else(|| {
+                frequencies.insert(word.to_owned(), 1);
+            });
+    }
+}
+
+#[rustfmt::skip]
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // Check for `result.map(_).unwrap_or_else(_)` use.
+    // single line case
+    let _ = res.map_or_else(|_e| 0, |x| x + 1);
+
+    // macro case
+    let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint
+}
+
+fn main() {
+    option_methods();
+    result_methods();
+}
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs
new file mode 100644
index 00000000000..0b892caf20e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs
@@ -0,0 +1,58 @@
+// run-rustfix
+// aux-build:option_helpers.rs
+
+#![warn(clippy::map_unwrap_or)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use std::collections::HashMap;
+
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or_else(_)` use.
+    // single line case
+    let _ = opt.map(|x| x + 1)
+        // Should lint even though this call is on a separate line.
+        .unwrap_or_else(|| 0);
+
+    // Macro case.
+    // Should not lint.
+    let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0);
+
+    // Issue #4144
+    {
+        let mut frequencies = HashMap::new();
+        let word = "foo";
+
+        frequencies
+            .get_mut(word)
+            .map(|count| {
+                *count += 1;
+            })
+            .unwrap_or_else(|| {
+                frequencies.insert(word.to_owned(), 1);
+            });
+    }
+}
+
+#[rustfmt::skip]
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // Check for `result.map(_).unwrap_or_else(_)` use.
+    // single line case
+    let _ = res.map(|x| x + 1)
+        // should lint even though this call is on a separate line
+        .unwrap_or_else(|_e| 0);
+
+    // macro case
+    let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint
+}
+
+fn main() {
+    option_methods();
+    result_methods();
+}
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr
new file mode 100644
index 00000000000..1837bc2ca3b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr
@@ -0,0 +1,22 @@
+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/map_unwrap_or_fixable.rs:17: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);
+   | |_____________________________^ help: try this: `opt.map_or_else(|| 0, |x| x + 1)`
+   |
+   = note: `-D clippy::map-unwrap-or` implied by `-D warnings`
+
+error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
+  --> $DIR/map_unwrap_or_fixable.rs:47:13
+   |
+LL |       let _ = res.map(|x| x + 1)
+   |  _____________^
+LL | |         // should lint even though this call is on a separate line
+LL | |         .unwrap_or_else(|_e| 0);
+   | |_______________________________^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/match_type_on_diag_item.stderr b/src/tools/clippy/tests/ui/match_type_on_diag_item.stderr
index 5e5fe9e3a3e..82465dbaf6e 100644
--- a/src/tools/clippy/tests/ui/match_type_on_diag_item.stderr
+++ b/src/tools/clippy/tests/ui/match_type_on_diag_item.stderr
@@ -2,7 +2,7 @@ error: usage of `utils::match_type()` on a type diagnostic item
   --> $DIR/match_type_on_diag_item.rs:41:17
    |
 LL |         let _ = match_type(cx, ty, &paths::VEC);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::vec_type)`
    |
 note: the lint level is defined here
   --> $DIR/match_type_on_diag_item.rs:1:9
@@ -15,19 +15,19 @@ error: usage of `utils::match_type()` on a type diagnostic item
   --> $DIR/match_type_on_diag_item.rs:42:17
    |
 LL |         let _ = match_type(cx, ty, &OPTION);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(option_type))`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::option_type)`
 
 error: usage of `utils::match_type()` on a type diagnostic item
   --> $DIR/match_type_on_diag_item.rs:43:17
    |
 LL |         let _ = match_type(cx, ty, &["core", "result", "Result"]);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(result_type))`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::result_type)`
 
 error: usage of `utils::match_type()` on a type diagnostic item
   --> $DIR/match_type_on_diag_item.rs:46:17
    |
 LL |         let _ = utils::match_type(cx, ty, rc_path);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(Rc))`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::Rc)`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 80dd2f744b3..d93e5b114ec 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -122,16 +122,13 @@ impl Mul<T> for T {
 fn filter_next() {
     let v = vec![3, 2, 1, 0, -1, -2, -3];
 
-    // Single-line case.
-    let _ = v.iter().filter(|&x| *x < 0).next();
-
     // Multi-line case.
     let _ = v.iter().filter(|&x| {
                                 *x < 0
                             }
                    ).next();
 
-    // Check that hat 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.filter().next();
 }
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
index 2a0a43e83a6..8a281c2dbd2 100644
--- a/src/tools/clippy/tests/ui/methods.stderr
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -8,27 +8,20 @@ LL | |     }
    |
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
-error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead.
+error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead.
   --> $DIR/methods.rs:126: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:129:13
-   |
 LL |       let _ = v.iter().filter(|&x| {
    |  _____________^
 LL | |                                 *x < 0
 LL | |                             }
 LL | |                    ).next();
    | |___________________________^
+   |
+   = note: `-D clippy::filter-next` implied by `-D warnings`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:146:22
+  --> $DIR/methods.rs:143:22
    |
 LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)`
@@ -36,25 +29,25 @@ LL |     let _ = v.iter().find(|&x| *x < 0).is_some();
    = note: `-D clippy::search-is-some` implied by `-D warnings`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:147:20
+  --> $DIR/methods.rs:144:20
    |
 LL |     let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:148:20
+  --> $DIR/methods.rs:145:20
    |
 LL |     let _ = (0..1).find(|x| *x == 0).is_some();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:149:22
+  --> $DIR/methods.rs:146:22
    |
 LL |     let _ = v.iter().find(|x| **x == 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)`
 
 error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:152:13
+  --> $DIR/methods.rs:149:13
    |
 LL |       let _ = v.iter().find(|&x| {
    |  _____________^
@@ -64,13 +57,13 @@ LL | |                    ).is_some();
    | |______________________________^
 
 error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:158:22
+  --> $DIR/methods.rs:155:22
    |
 LL |     let _ = v.iter().position(|&x| x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:161:13
+  --> $DIR/methods.rs:158:13
    |
 LL |       let _ = v.iter().position(|&x| {
    |  _____________^
@@ -80,13 +73,13 @@ LL | |                    ).is_some();
    | |______________________________^
 
 error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:167:22
+  --> $DIR/methods.rs:164:22
    |
 LL |     let _ = v.iter().rposition(|&x| x < 0).is_some();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)`
 
 error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`.
-  --> $DIR/methods.rs:170:13
+  --> $DIR/methods.rs:167:13
    |
 LL |       let _ = v.iter().rposition(|&x| {
    |  _____________^
@@ -95,5 +88,5 @@ LL | |                                }
 LL | |                    ).is_some();
    | |______________________________^
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/methods_fixable.fixed b/src/tools/clippy/tests/ui/methods_fixable.fixed
new file mode 100644
index 00000000000..ee7c1b0da6d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods_fixable.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+
+#![warn(clippy::filter_next)]
+
+/// Checks implementation of `FILTER_NEXT` lint.
+fn main() {
+    let v = vec![3, 2, 1, 0, -1, -2, -3];
+
+    // Single-line case.
+    let _ = v.iter().find(|&x| *x < 0);
+}
diff --git a/src/tools/clippy/tests/ui/methods_fixable.rs b/src/tools/clippy/tests/ui/methods_fixable.rs
new file mode 100644
index 00000000000..6d0f1b7bd51
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods_fixable.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+
+#![warn(clippy::filter_next)]
+
+/// Checks implementation of `FILTER_NEXT` lint.
+fn main() {
+    let v = vec![3, 2, 1, 0, -1, -2, -3];
+
+    // Single-line case.
+    let _ = v.iter().filter(|&x| *x < 0).next();
+}
diff --git a/src/tools/clippy/tests/ui/methods_fixable.stderr b/src/tools/clippy/tests/ui/methods_fixable.stderr
new file mode 100644
index 00000000000..70e7c3dea54
--- /dev/null
+++ b/src/tools/clippy/tests/ui/methods_fixable.stderr
@@ -0,0 +1,10 @@
+error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead.
+  --> $DIR/methods_fixable.rs:10:13
+   |
+LL |     let _ = v.iter().filter(|&x| *x < 0).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)`
+   |
+   = note: `-D clippy::filter-next` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index a7fb00a2705..47e7460fa7a 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
 #![allow(clippy::redundant_closure)]
+#![allow(clippy::ref_option_ref)]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
     string.map_or((false, "hello"), |x| (true, x))
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 895fd86321f..e2f8dec3b93 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
 #![allow(clippy::redundant_closure)]
+#![allow(clippy::ref_option_ref)]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
     if let Some(x) = string {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index b69fe767682..7aab068800a 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:6:5
+  --> $DIR/option_if_let_else.rs:7:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,7 +11,7 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:16:12
+  --> $DIR/option_if_let_else.rs:17:12
    |
 LL |       } else if let Some(x) = string {
    |  ____________^
@@ -22,19 +22,19 @@ LL | |     }
    | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:24:13
+  --> $DIR/option_if_let_else.rs:25:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:25:13
+  --> $DIR/option_if_let_else.rs:26:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:26:13
+  --> $DIR/option_if_let_else.rs:27:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -54,13 +54,13 @@ LL |     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:32:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:33:13
+  --> $DIR/option_if_let_else.rs:34:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -80,7 +80,7 @@ LL |     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:39:13
+  --> $DIR/option_if_let_else.rs:40:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -100,7 +100,7 @@ LL |     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:48:5
+  --> $DIR/option_if_let_else.rs:49:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -119,7 +119,7 @@ LL |     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:61:13
+  --> $DIR/option_if_let_else.rs:62:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -131,7 +131,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:70:13
+  --> $DIR/option_if_let_else.rs:71:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -154,7 +154,7 @@ LL |     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:99:13
+  --> $DIR/option_if_let_else.rs:100:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
diff --git a/src/tools/clippy/tests/ui/option_map_or_none.stderr b/src/tools/clippy/tests/ui/option_map_or_none.stderr
index 6f707987dbc..1cba29412b8 100644
--- a/src/tools/clippy/tests/ui/option_map_or_none.stderr
+++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr
@@ -1,4 +1,4 @@
-error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead
   --> $DIR/option_map_or_none.rs:10:13
    |
 LL |     let _ = opt.map_or(None, |x| Some(x + 1));
@@ -6,7 +6,7 @@ LL |     let _ = opt.map_or(None, |x| Some(x + 1));
    |
    = note: `-D clippy::option-map-or-none` implied by `-D warnings`
 
-error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead
+error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead
   --> $DIR/option_map_or_none.rs:13:13
    |
 LL |       let _ = opt.map_or(None, |x| {
diff --git a/src/tools/clippy/tests/ui/ref_option_ref.rs b/src/tools/clippy/tests/ui/ref_option_ref.rs
new file mode 100644
index 00000000000..b2c275d68af
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option_ref.rs
@@ -0,0 +1,47 @@
+#![allow(unused)]
+#![warn(clippy::ref_option_ref)]
+
+// This lint is not tagged as run-rustfix because automatically
+// changing the type of a variable would also means changing
+// all usages of this variable to match and This is not handled
+// by this lint.
+
+static THRESHOLD: i32 = 10;
+static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD);
+const CONST_THRESHOLD: &i32 = &10;
+const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD);
+
+type RefOptRefU32<'a> = &'a Option<&'a u32>;
+type RefOptRef<'a, T> = &'a Option<&'a T>;
+
+fn foo(data: &Option<&u32>) {}
+
+fn bar(data: &u32) -> &Option<&u32> {
+    &None
+}
+
+struct StructRef<'a> {
+    data: &'a Option<&'a u32>,
+}
+
+struct StructTupleRef<'a>(u32, &'a Option<&'a u32>);
+
+enum EnumRef<'a> {
+    Variant1(u32),
+    Variant2(&'a Option<&'a u32>),
+}
+
+trait RefOptTrait {
+    type A;
+    fn foo(&self, _: Self::A);
+}
+
+impl RefOptTrait for u32 {
+    type A = &'static Option<&'static Self>;
+
+    fn foo(&self, _: Self::A) {}
+}
+
+fn main() {
+    let x: &Option<&u32> = &None;
+}
diff --git a/src/tools/clippy/tests/ui/ref_option_ref.stderr b/src/tools/clippy/tests/ui/ref_option_ref.stderr
new file mode 100644
index 00000000000..4e7fc800061
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_option_ref.stderr
@@ -0,0 +1,70 @@
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:10:23
+   |
+LL | static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD);
+   |                       ^^^^^^^^^^^^^ help: try: `Option<&i32>`
+   |
+   = note: `-D clippy::ref-option-ref` implied by `-D warnings`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:12:18
+   |
+LL | const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD);
+   |                  ^^^^^^^^^^^^^ help: try: `Option<&i32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:14:25
+   |
+LL | type RefOptRefU32<'a> = &'a Option<&'a u32>;
+   |                         ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:15:25
+   |
+LL | type RefOptRef<'a, T> = &'a Option<&'a T>;
+   |                         ^^^^^^^^^^^^^^^^^ help: try: `Option<&'a T>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:17:14
+   |
+LL | fn foo(data: &Option<&u32>) {}
+   |              ^^^^^^^^^^^^^ help: try: `Option<&u32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:19:23
+   |
+LL | fn bar(data: &u32) -> &Option<&u32> {
+   |                       ^^^^^^^^^^^^^ help: try: `Option<&u32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:24:11
+   |
+LL |     data: &'a Option<&'a u32>,
+   |           ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:27:32
+   |
+LL | struct StructTupleRef<'a>(u32, &'a Option<&'a u32>);
+   |                                ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:31:14
+   |
+LL |     Variant2(&'a Option<&'a u32>),
+   |              ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:40:14
+   |
+LL |     type A = &'static Option<&'static Self>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'static Self>`
+
+error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`
+  --> $DIR/ref_option_ref.rs:46:12
+   |
+LL |     let x: &Option<&u32> = &None;
+   |            ^^^^^^^^^^^^^ help: try: `Option<&u32>`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/single_char_add_str.fixed b/src/tools/clippy/tests/ui/single_char_add_str.fixed
new file mode 100644
index 00000000000..63a6d37a9cc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_char_add_str.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+#![warn(clippy::single_char_add_str)]
+
+macro_rules! get_string {
+    () => {
+        String::from("Hello world!")
+    };
+}
+
+fn main() {
+    // `push_str` tests
+
+    let mut string = String::new();
+    string.push('R');
+    string.push('\'');
+
+    string.push('u');
+    string.push_str("st");
+    string.push_str("");
+    string.push('\x52');
+    string.push('\u{0052}');
+    string.push('a');
+
+    get_string!().push('ö');
+
+    // `insert_str` tests
+
+    let mut string = String::new();
+    string.insert(0, 'R');
+    string.insert(1, '\'');
+
+    string.insert(0, 'u');
+    string.insert_str(2, "st");
+    string.insert_str(0, "");
+    string.insert(0, '\x52');
+    string.insert(0, '\u{0052}');
+    let x: usize = 2;
+    string.insert(x, 'a');
+    const Y: usize = 1;
+    string.insert(Y, 'a');
+    string.insert(Y, '"');
+    string.insert(Y, '\'');
+
+    get_string!().insert(1, '?');
+}
diff --git a/src/tools/clippy/tests/ui/single_char_add_str.rs b/src/tools/clippy/tests/ui/single_char_add_str.rs
new file mode 100644
index 00000000000..a799ea7d885
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_char_add_str.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+#![warn(clippy::single_char_add_str)]
+
+macro_rules! get_string {
+    () => {
+        String::from("Hello world!")
+    };
+}
+
+fn main() {
+    // `push_str` tests
+
+    let mut string = String::new();
+    string.push_str("R");
+    string.push_str("'");
+
+    string.push('u');
+    string.push_str("st");
+    string.push_str("");
+    string.push_str("\x52");
+    string.push_str("\u{0052}");
+    string.push_str(r##"a"##);
+
+    get_string!().push_str("ö");
+
+    // `insert_str` tests
+
+    let mut string = String::new();
+    string.insert_str(0, "R");
+    string.insert_str(1, "'");
+
+    string.insert(0, 'u');
+    string.insert_str(2, "st");
+    string.insert_str(0, "");
+    string.insert_str(0, "\x52");
+    string.insert_str(0, "\u{0052}");
+    let x: usize = 2;
+    string.insert_str(x, r##"a"##);
+    const Y: usize = 1;
+    string.insert_str(Y, r##"a"##);
+    string.insert_str(Y, r##"""##);
+    string.insert_str(Y, r##"'"##);
+
+    get_string!().insert_str(1, "?");
+}
diff --git a/src/tools/clippy/tests/ui/single_char_add_str.stderr b/src/tools/clippy/tests/ui/single_char_add_str.stderr
new file mode 100644
index 00000000000..55d91583ad0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/single_char_add_str.stderr
@@ -0,0 +1,94 @@
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:14:5
+   |
+LL |     string.push_str("R");
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')`
+   |
+   = note: `-D clippy::single-char-add-str` implied by `-D warnings`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:15:5
+   |
+LL |     string.push_str("'");
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:20:5
+   |
+LL |     string.push_str("/x52");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:21:5
+   |
+LL |     string.push_str("/u{0052}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:22:5
+   |
+LL |     string.push_str(r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:24:5
+   |
+LL |     get_string!().push_str("ö");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:29:5
+   |
+LL |     string.insert_str(0, "R");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:30:5
+   |
+LL |     string.insert_str(1, "'");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:35:5
+   |
+LL |     string.insert_str(0, "/x52");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:36:5
+   |
+LL |     string.insert_str(0, "/u{0052}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:38:5
+   |
+LL |     string.insert_str(x, r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:40:5
+   |
+LL |     string.insert_str(Y, r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:41:5
+   |
+LL |     string.insert_str(Y, r##"""##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:42:5
+   |
+LL |     string.insert_str(Y, r##"'"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '/'')`
+
+error: calling `insert_str()` using a single-character string literal
+  --> $DIR/single_char_add_str.rs:44:5
+   |
+LL |     get_string!().insert_str(1, "?");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
index 3871c4f2268..d8b5f19e144 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.fixed
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -12,15 +12,9 @@ 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_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("💣");
+    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');
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
index 32afe339cd8..a7bc73e3756 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.rs
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -12,12 +12,6 @@ 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_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("💣");
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
index fe7211c53f8..ee4e7e50efd 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.stderr
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -7,160 +7,178 @@ LL |     x.split("x");
    = note: `-D clippy::single-char-pattern` implied by `-D warnings`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:26:16
+  --> $DIR/single_char_pattern.rs:15:13
+   |
+LL |     x.split("ß");
+   |             ^^^ help: try using a `char` instead: `'ß'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:16:13
+   |
+LL |     x.split("ℝ");
+   |             ^^^ help: try using a `char` instead: `'ℝ'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:17:13
+   |
+LL |     x.split("💣");
+   |             ^^^^ help: try using a `char` instead: `'💣'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:20:16
    |
 LL |     x.contains("x");
    |                ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:27:19
+  --> $DIR/single_char_pattern.rs:21:19
    |
 LL |     x.starts_with("x");
    |                   ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:28:17
+  --> $DIR/single_char_pattern.rs:22:17
    |
 LL |     x.ends_with("x");
    |                 ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:29:12
+  --> $DIR/single_char_pattern.rs:23:12
    |
 LL |     x.find("x");
    |            ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:30:13
+  --> $DIR/single_char_pattern.rs:24:13
    |
 LL |     x.rfind("x");
    |             ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:31:14
+  --> $DIR/single_char_pattern.rs:25:14
    |
 LL |     x.rsplit("x");
    |              ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:32:24
+  --> $DIR/single_char_pattern.rs:26:24
    |
 LL |     x.split_terminator("x");
    |                        ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:33:25
+  --> $DIR/single_char_pattern.rs:27:25
    |
 LL |     x.rsplit_terminator("x");
    |                         ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:34:17
+  --> $DIR/single_char_pattern.rs:28:17
    |
 LL |     x.splitn(0, "x");
    |                 ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:35:18
+  --> $DIR/single_char_pattern.rs:29:18
    |
 LL |     x.rsplitn(0, "x");
    |                  ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:36:15
+  --> $DIR/single_char_pattern.rs:30:15
    |
 LL |     x.matches("x");
    |               ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:37:16
+  --> $DIR/single_char_pattern.rs:31:16
    |
 LL |     x.rmatches("x");
    |                ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:38:21
+  --> $DIR/single_char_pattern.rs:32:21
    |
 LL |     x.match_indices("x");
    |                     ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:39:22
+  --> $DIR/single_char_pattern.rs:33:22
    |
 LL |     x.rmatch_indices("x");
    |                      ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:40:26
+  --> $DIR/single_char_pattern.rs:34:26
    |
 LL |     x.trim_start_matches("x");
    |                          ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:41:24
+  --> $DIR/single_char_pattern.rs:35:24
    |
 LL |     x.trim_end_matches("x");
    |                        ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:43:13
+  --> $DIR/single_char_pattern.rs:37:13
    |
 LL |     x.split("/n");
    |             ^^^^ help: try using a `char` instead: `'/n'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:44:13
+  --> $DIR/single_char_pattern.rs:38: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
+  --> $DIR/single_char_pattern.rs:39: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
+  --> $DIR/single_char_pattern.rs:44:31
    |
 LL |     x.replace(";", ",").split(","); // issue #2978
    |                               ^^^ help: try using a `char` instead: `','`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:51:19
+  --> $DIR/single_char_pattern.rs:45:19
    |
 LL |     x.starts_with("/x03"); // issue #2996
    |                   ^^^^^^ help: try using a `char` instead: `'/x03'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:58:13
+  --> $DIR/single_char_pattern.rs:52:13
    |
 LL |     x.split(r"a");
    |             ^^^^ help: try using a `char` instead: `'a'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:59:13
+  --> $DIR/single_char_pattern.rs:53:13
    |
 LL |     x.split(r#"a"#);
    |             ^^^^^^ help: try using a `char` instead: `'a'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:60:13
+  --> $DIR/single_char_pattern.rs:54:13
    |
 LL |     x.split(r###"a"###);
    |             ^^^^^^^^^^ help: try using a `char` instead: `'a'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:61:13
+  --> $DIR/single_char_pattern.rs:55:13
    |
 LL |     x.split(r###"'"###);
    |             ^^^^^^^^^^ help: try using a `char` instead: `'/''`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:62:13
+  --> $DIR/single_char_pattern.rs:56:13
    |
 LL |     x.split(r###"#"###);
    |             ^^^^^^^^^^ help: try using a `char` instead: `'#'`
 
-error: aborting due to 27 previous errors
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_char_push_str.fixed b/src/tools/clippy/tests/ui/single_char_push_str.fixed
deleted file mode 100644
index 0812c026a64..00000000000
--- a/src/tools/clippy/tests/ui/single_char_push_str.fixed
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-rustfix
-#![warn(clippy::single_char_push_str)]
-
-fn main() {
-    let mut string = String::new();
-    string.push('R');
-    string.push('\'');
-
-    string.push('u');
-    string.push_str("st");
-    string.push_str("");
-    string.push('\x52');
-    string.push('\u{0052}');
-    string.push('a');
-}
diff --git a/src/tools/clippy/tests/ui/single_char_push_str.rs b/src/tools/clippy/tests/ui/single_char_push_str.rs
deleted file mode 100644
index ab293bbe4ee..00000000000
--- a/src/tools/clippy/tests/ui/single_char_push_str.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-rustfix
-#![warn(clippy::single_char_push_str)]
-
-fn main() {
-    let mut string = String::new();
-    string.push_str("R");
-    string.push_str("'");
-
-    string.push('u');
-    string.push_str("st");
-    string.push_str("");
-    string.push_str("\x52");
-    string.push_str("\u{0052}");
-    string.push_str(r##"a"##);
-}
diff --git a/src/tools/clippy/tests/ui/single_char_push_str.stderr b/src/tools/clippy/tests/ui/single_char_push_str.stderr
deleted file mode 100644
index 0e9bdaa23e7..00000000000
--- a/src/tools/clippy/tests/ui/single_char_push_str.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_push_str.rs:6:5
-   |
-LL |     string.push_str("R");
-   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')`
-   |
-   = note: `-D clippy::single-char-push-str` implied by `-D warnings`
-
-error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_push_str.rs:7:5
-   |
-LL |     string.push_str("'");
-   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
-
-error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_push_str.rs:12:5
-   |
-LL |     string.push_str("/x52");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
-
-error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_push_str.rs:13:5
-   |
-LL |     string.push_str("/u{0052}");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
-
-error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_push_str.rs:14:5
-   |
-LL |     string.push_str(r##"a"##);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
-
-error: aborting due to 5 previous errors
-
diff --git a/src/tools/clippy/tests/ui/skip_while_next.stderr b/src/tools/clippy/tests/ui/skip_while_next.stderr
index a6b7bcd63ff..269cc13468b 100644
--- a/src/tools/clippy/tests/ui/skip_while_next.stderr
+++ b/src/tools/clippy/tests/ui/skip_while_next.stderr
@@ -1,13 +1,13 @@
-error: called `skip_while(p).next()` on an `Iterator`
+error: called `skip_while(<p>).next()` on an `Iterator`
   --> $DIR/skip_while_next.rs:14:13
    |
 LL |     let _ = v.iter().skip_while(|&x| *x < 0).next();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::skip-while-next` implied by `-D warnings`
-   = help: this is more succinctly expressed by calling `.find(!p)` instead
+   = help: this is more succinctly expressed by calling `.find(!<p>)` instead
 
-error: called `skip_while(p).next()` on an `Iterator`
+error: called `skip_while(<p>).next()` on an `Iterator`
   --> $DIR/skip_while_next.rs:17:13
    |
 LL |       let _ = v.iter().skip_while(|&x| {
@@ -17,7 +17,7 @@ LL | |                             }
 LL | |                    ).next();
    | |___________________________^
    |
-   = help: this is more succinctly expressed by calling `.find(!p)` instead
+   = help: this is more succinctly expressed by calling `.find(!<p>)` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
index 33605aca019..b129d95c560 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed
@@ -1,7 +1,17 @@
 // run-rustfix
+// aux-build:macro_rules.rs
 
 #![warn(clippy::toplevel_ref_arg)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! gen_binding {
+    () => {
+        let _y = &42;
+    };
+}
+
 fn main() {
     // Closures should not warn
     let y = |ref x| println!("{:?}", x);
@@ -26,4 +36,15 @@ fn main() {
 
     // ok
     for ref _x in 0..10 {}
+
+    // lint in macro
+    #[allow(unused)]
+    {
+        gen_binding!();
+    }
+
+    // do not lint in external macro
+    {
+        ref_arg_binding!();
+    }
 }
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
index 59759f11893..73eb4ff7306 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs
@@ -1,7 +1,17 @@
 // run-rustfix
+// aux-build:macro_rules.rs
 
 #![warn(clippy::toplevel_ref_arg)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! gen_binding {
+    () => {
+        let ref _y = 42;
+    };
+}
+
 fn main() {
     // Closures should not warn
     let y = |ref x| println!("{:?}", x);
@@ -26,4 +36,15 @@ fn main() {
 
     // ok
     for ref _x in 0..10 {}
+
+    // lint in macro
+    #[allow(unused)]
+    {
+        gen_binding!();
+    }
+
+    // do not lint in external macro
+    {
+        ref_arg_binding!();
+    }
 }
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr
index 19d69496709..15cb933fedc 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr
@@ -1,5 +1,5 @@
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:10:9
+  --> $DIR/toplevel_ref_arg.rs:20:9
    |
 LL |     let ref _x = 1;
    |     ----^^^^^^----- help: try: `let _x = &1;`
@@ -7,28 +7,39 @@ LL |     let ref _x = 1;
    = 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:12:9
+  --> $DIR/toplevel_ref_arg.rs:22:9
    |
 LL |     let ref _y: (&_, u8) = (&1, 2);
    |     ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:14:9
+  --> $DIR/toplevel_ref_arg.rs:24:9
    |
 LL |     let ref _z = 1 + 2;
    |     ----^^^^^^--------- help: try: `let _z = &(1 + 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:16:9
+  --> $DIR/toplevel_ref_arg.rs:26:9
    |
 LL |     let ref mut _z = 1 + 2;
    |     ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);`
 
 error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
-  --> $DIR/toplevel_ref_arg.rs:21:9
+  --> $DIR/toplevel_ref_arg.rs:31:9
    |
 LL |     let ref _x = vec![1, 2, 3];
    |     ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];`
 
-error: aborting due to 5 previous errors
+error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead
+  --> $DIR/toplevel_ref_arg.rs:11:13
+   |
+LL |         let ref _y = 42;
+   |         ----^^^^^^------ help: try: `let _y = &42;`
+...
+LL |         gen_binding!();
+   |         --------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs
index 42cac2ba4de..1a493fbce0e 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs
@@ -1,11 +1,33 @@
+// aux-build:macro_rules.rs
+
 #![warn(clippy::toplevel_ref_arg)]
 #![allow(unused)]
 
+#[macro_use]
+extern crate macro_rules;
+
 fn the_answer(ref mut x: u8) {
     *x = 42;
 }
 
+macro_rules! gen_function {
+    () => {
+        fn fun_example(ref _x: usize) {}
+    };
+}
+
 fn main() {
     let mut x = 0;
     the_answer(x);
+
+    // lint in macro
+    #[allow(unused)]
+    {
+        gen_function!();
+    }
+
+    // do not lint in external macro
+    {
+        ref_arg_function!();
+    }
 }
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
index 295e2f35608..6c36141a58c 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
@@ -1,10 +1,21 @@
 error: `ref` directly on a function argument is ignored. Consider using a reference type instead.
-  --> $DIR/toplevel_ref_arg_non_rustfix.rs:4:15
+  --> $DIR/toplevel_ref_arg_non_rustfix.rs:9:15
    |
 LL | fn the_answer(ref mut x: u8) {
    |               ^^^^^^^^^
    |
    = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
 
-error: aborting due to previous error
+error: `ref` directly on a function argument is ignored. Consider using a reference type instead.
+  --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24
+   |
+LL |         fn fun_example(ref _x: usize) {}
+   |                        ^^^^^^
+...
+LL |         gen_function!();
+   |         ---------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed
index 07f2791786d..7afc5361356 100644
--- a/src/tools/clippy/tests/ui/unused_unit.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.fixed
@@ -15,35 +15,35 @@
 struct Unitter;
 impl Unitter {
     #[allow(clippy::no_effect)]
-    pub fn get_unit<F: Fn() , G>(&self, f: F, _g: G) 
-    where G: Fn()  {
-        let _y: &dyn Fn()  = &f;
+    pub fn get_unit<F: Fn(), G>(&self, f: F, _g: G)
+    where G: Fn() {
+        let _y: &dyn Fn() = &f;
         (); // this should not lint, as it's not in return type position
     }
 }
 
 impl Into<()> for Unitter {
     #[rustfmt::skip]
-    fn into(self)  {
+    fn into(self) {
         
     }
 }
 
 trait Trait {
-    fn redundant<F: FnOnce() , G, H>(&self, _f: F, _g: G, _h: H)
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
     where
-        G: FnMut() ,
-        H: Fn() ;
+        G: FnMut(),
+        H: Fn();
 }
 
 impl Trait for Unitter {
-    fn redundant<F: FnOnce() , G, H>(&self, _f: F, _g: G, _h: H)
+    fn redundant<F: FnOnce(), G, H>(&self, _f: F, _g: G, _h: H)
     where
-        G: FnMut() ,
-        H: Fn()  {}
+        G: FnMut(),
+        H: Fn() {}
 }
 
-fn return_unit()  {  }
+fn return_unit() {  }
 
 #[allow(clippy::needless_return)]
 #[allow(clippy::never_loop)]
@@ -70,3 +70,12 @@ fn foo() {
         recv(rx) -> _x => ()
     }
 }
+
+#[rustfmt::skip]
+fn test(){}
+
+#[rustfmt::skip]
+fn test2(){}
+
+#[rustfmt::skip]
+fn test3(){}
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs
index e2c6afb020f..96cef1ed5a5 100644
--- a/src/tools/clippy/tests/ui/unused_unit.rs
+++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -70,3 +70,12 @@ fn foo() {
         recv(rx) -> _x => ()
     }
 }
+
+#[rustfmt::skip]
+fn test()->(){}
+
+#[rustfmt::skip]
+fn test2() ->(){}
+
+#[rustfmt::skip]
+fn test3()-> (){}
diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr
index 81e6738e6bf..c45634c2b6d 100644
--- a/src/tools/clippy/tests/ui/unused_unit.stderr
+++ b/src/tools/clippy/tests/ui/unused_unit.stderr
@@ -1,8 +1,8 @@
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:18:29
+  --> $DIR/unused_unit.rs:18:28
    |
 LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                             ^^^^^ help: remove the `-> ()`
+   |                            ^^^^^^ help: remove the `-> ()`
    |
 note: the lint level is defined here
   --> $DIR/unused_unit.rs:12:9
@@ -11,28 +11,28 @@ LL | #![deny(clippy::unused_unit)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:19:19
+  --> $DIR/unused_unit.rs:19:18
    |
 LL |     where G: Fn() -> () {
-   |                   ^^^^^ help: remove the `-> ()`
+   |                  ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:18:59
+  --> $DIR/unused_unit.rs:18:58
    |
 LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                                                           ^^^^^ help: remove the `-> ()`
+   |                                                          ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:20:27
+  --> $DIR/unused_unit.rs:20:26
    |
 LL |         let _y: &dyn Fn() -> () = &f;
-   |                           ^^^^^ help: remove the `-> ()`
+   |                          ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:27:19
+  --> $DIR/unused_unit.rs:27:18
    |
 LL |     fn into(self) -> () {
-   |                   ^^^^^ help: remove the `-> ()`
+   |                  ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit expression
   --> $DIR/unused_unit.rs:28:9
@@ -41,46 +41,46 @@ LL |         ()
    |         ^^ help: remove the final `()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:33:30
+  --> $DIR/unused_unit.rs:33:29
    |
 LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
-   |                              ^^^^^ help: remove the `-> ()`
+   |                             ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:35:20
+  --> $DIR/unused_unit.rs:35:19
    |
 LL |         G: FnMut() -> (),
-   |                    ^^^^^ help: remove the `-> ()`
+   |                   ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:36:17
+  --> $DIR/unused_unit.rs:36:16
    |
 LL |         H: Fn() -> ();
-   |                 ^^^^^ help: remove the `-> ()`
+   |                ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:40:30
+  --> $DIR/unused_unit.rs:40:29
    |
 LL |     fn redundant<F: FnOnce() -> (), G, H>(&self, _f: F, _g: G, _h: H)
-   |                              ^^^^^ help: remove the `-> ()`
+   |                             ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:42:20
+  --> $DIR/unused_unit.rs:42:19
    |
 LL |         G: FnMut() -> (),
-   |                    ^^^^^ help: remove the `-> ()`
+   |                   ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:43:17
+  --> $DIR/unused_unit.rs:43:16
    |
 LL |         H: Fn() -> () {}
-   |                 ^^^^^ help: remove the `-> ()`
+   |                ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:46:18
+  --> $DIR/unused_unit.rs:46:17
    |
 LL | fn return_unit() -> () { () }
-   |                  ^^^^^ help: remove the `-> ()`
+   |                 ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit expression
   --> $DIR/unused_unit.rs:46:26
@@ -100,5 +100,23 @@ error: unneeded `()`
 LL |     return();
    |           ^^ help: remove the `()`
 
-error: aborting due to 16 previous errors
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:75:10
+   |
+LL | fn test()->(){}
+   |          ^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:78:11
+   |
+LL | fn test2() ->(){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: unneeded unit return type
+  --> $DIR/unused_unit.rs:81:11
+   |
+LL | fn test3()-> (){}
+   |           ^^^^^ help: remove the `-> ()`
+
+error: aborting due to 19 previous errors