Repository: paritytech/ink
Pull request #884 (2021-08-02 05:01:48)

Run clippy with `--all-targets`
We were not running clippy on all targets, this mostly had the effect of test code being excluded.

Edit: I converted the PR to draft to figure out an issue with `trybuild`.


Patch:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fed092393c..7536d82881 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,7 +24,7 @@ variables:
   # this var is changed to "-:staging" when the CI image gets rebuilt
   # read more https://github.com/paritytech/scripts/pull/244
   ALL_CRATES:                      "${PURELY_STD_CRATES} ${ALSO_WASM_CRATES}"
-  DELEGATOR_SUBCONTRACTS:           "accumulator adder subber"
+  DELEGATOR_SUBCONTRACTS:          "accumulator adder subber"
 
 workflow:
   rules:
@@ -191,7 +191,7 @@ clippy-std:
       artifacts:                   false
   script:
     - for crate in ${ALL_CRATES}; do
-        cargo clippy --verbose --all-features --manifest-path crates/${crate}/Cargo.toml -- -D warnings;
+        cargo clippy --verbose --all-targets --all-features --manifest-path crates/${crate}/Cargo.toml -- -D warnings;
       done
 
 clippy-wasm:
@@ -269,10 +269,10 @@ examples-clippy-std:
       artifacts:                   false
   script:
     - for example in examples/*/; do
-        cargo clippy --verbose --manifest-path ${example}/Cargo.toml -- -D warnings;
+        cargo clippy --verbose --all-targets --manifest-path ${example}/Cargo.toml -- -D warnings;
       done
     - for contract in ${DELEGATOR_SUBCONTRACTS}; do
-        cargo clippy --verbose --manifest-path examples/delegator/${contract}/Cargo.toml -- -D warnings;
+        cargo clippy --verbose --all-targets --manifest-path examples/delegator/${contract}/Cargo.toml -- -D warnings;
       done
 
 examples-clippy-wasm:
diff --git a/crates/allocator/Cargo.toml b/crates/allocator/Cargo.toml
index c7dbc37a30..d4c0d0a7e5 100644
--- a/crates/allocator/Cargo.toml
+++ b/crates/allocator/Cargo.toml
@@ -18,7 +18,12 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
 cfg-if = "1.0"
 wee_alloc = { version = "0.4", default-features = false, optional = true }
 
+[dev-dependencies]
+quickcheck = "1"
+quickcheck_macros = "1"
+
 [features]
 default = ["std"]
 std = []
 wee-alloc = ["wee_alloc"]
+ink-fuzz-tests = ["std"]
diff --git a/crates/allocator/src/bump.rs b/crates/allocator/src/bump.rs
index 63b4d24101..a573689573 100644
--- a/crates/allocator/src/bump.rs
+++ b/crates/allocator/src/bump.rs
@@ -121,7 +121,7 @@ impl InnerAlloc {
         let alloc_end = alloc_start.checked_add(aligned_size)?;
 
         if alloc_end > self.upper_limit {
-            let required_pages = (aligned_size + PAGE_SIZE - 1) / PAGE_SIZE;
+            let required_pages = required_pages(aligned_size)?;
             let page_start = self.request_pages(required_pages)?;
 
             self.upper_limit = required_pages
@@ -137,9 +137,36 @@ impl InnerAlloc {
     }
 }
 
+/// Calculates the number of pages of memory needed for an allocation of `size` bytes.
+///
+/// This function rounds up to the next page. For example, if we have an allocation of
+/// `size = PAGE_SIZE / 2` this function will indicate that one page is required to satisfy
+/// the allocation.
+#[inline]
+fn required_pages(size: usize) -> Option<usize> {
+    size.checked_add(PAGE_SIZE - 1)
+        .and_then(|num| num.checked_div(PAGE_SIZE))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
+    use std::mem::size_of;
+
+    #[test]
+    fn can_alloc_no_bytes() {
+        let mut inner = InnerAlloc::new();
+
+        let layout = Layout::new::<()>();
+        assert_eq!(inner.alloc(layout), Some(0));
+
+        let expected_limit =
+            PAGE_SIZE * required_pages(layout.pad_to_align().size()).unwrap();
+        assert_eq!(inner.upper_limit, expected_limit);
+
+        let expected_alloc_start = size_of::<()>();
+        assert_eq!(inner.next, expected_alloc_start);
+    }
 
     #[test]
     fn can_alloc_a_byte() {
@@ -148,10 +175,11 @@ mod tests {
         let layout = Layout::new::<u8>();
         assert_eq!(inner.alloc(layout), Some(0));
 
-        let expected_limit = PAGE_SIZE;
+        let expected_limit =
+            PAGE_SIZE * required_pages(layout.pad_to_align().size()).unwrap();
         assert_eq!(inner.upper_limit, expected_limit);
 
-        let expected_alloc_start = std::mem::size_of::<u8>();
+        let expected_alloc_start = size_of::<u8>();
         assert_eq!(inner.next, expected_alloc_start);
     }
 
@@ -166,16 +194,18 @@ mod tests {
         }
 
         let layout = Layout::new::<FooBarBaz>();
+        let mut total_size = 0;
 
         let allocations = 3;
         for _ in 0..allocations {
             assert!(inner.alloc(layout).is_some());
+            total_size += layout.pad_to_align().size();
         }
 
-        let expected_limit = PAGE_SIZE;
+        let expected_limit = PAGE_SIZE * required_pages(total_size).unwrap();
         assert_eq!(inner.upper_limit, expected_limit);
 
-        let expected_alloc_start = allocations * std::mem::size_of::<FooBarBaz>();
+        let expected_alloc_start = allocations * size_of::<FooBarBaz>();
         assert_eq!(inner.next, expected_alloc_start);
     }
 
@@ -191,10 +221,11 @@ mod tests {
         let layout = Layout::new::<Foo>();
         assert_eq!(inner.alloc(layout), Some(0));
 
-        let expected_limit = PAGE_SIZE;
+        let expected_limit =
+            PAGE_SIZE * required_pages(layout.pad_to_align().size()).unwrap();
         assert_eq!(inner.upper_limit, expected_limit);
 
-        let expected_alloc_start = std::mem::size_of::<Foo>();
+        let expected_alloc_start = size_of::<Foo>();
         assert_eq!(inner.next, expected_alloc_start);
 
         // Now we'll allocate two bytes which will push us over to the next page
@@ -206,7 +237,7 @@ mod tests {
 
         // Notice that we start the allocation on the second page, instead of making use of the
         // remaining byte on the first page
-        let expected_alloc_start = PAGE_SIZE + std::mem::size_of::<u16>();
+        let expected_alloc_start = PAGE_SIZE + size_of::<u16>();
         assert_eq!(inner.next, expected_alloc_start);
     }
 
@@ -221,10 +252,11 @@ mod tests {
         let layout = Layout::new::<Foo>();
         assert_eq!(inner.alloc(layout), Some(0));
 
-        let expected_limit = 2 * PAGE_SIZE;
+        let expected_limit =
+            PAGE_SIZE * required_pages(layout.pad_to_align().size()).unwrap();
         assert_eq!(inner.upper_limit, expected_limit);
 
-        let expected_alloc_start = std::mem::size_of::<Foo>();
+        let expected_alloc_start = size_of::<Foo>();
         assert_eq!(inner.next, expected_alloc_start);
 
         // Now we want to make sure that the state of our allocator is correct for any subsequent
@@ -235,7 +267,260 @@ mod tests {
         let expected_limit = 3 * PAGE_SIZE;
         assert_eq!(inner.upper_limit, expected_limit);
 
-        let expected_alloc_start = 2 * PAGE_SIZE + std::mem::size_of::<u8>();
+        let expected_alloc_start = 2 * PAGE_SIZE + size_of::<u8>();
         assert_eq!(inner.next, expected_alloc_start);
     }
 }
+
+#[cfg(all(test, feature = "ink-fuzz-tests"))]
+mod fuzz_tests {
+    use super::*;
+    use quickcheck::{
+        quickcheck,
+        TestResult,
+    };
+    use std::mem::size_of;
+
+    const FROM_SIZE_ALIGN_EXPECT: &str =
+        "The rounded value of `size` cannot be more than `usize::MAX` since we have
+        checked that it is a PAGE_SIZE less than `usize::MAX`; Alignment is a
+        non-zero, power of two.";
+
+    #[quickcheck]
+    fn should_allocate_arbitrary_sized_bytes(n: usize) -> TestResult {
+        // If `n` is going to overflow we don't want to check it here (we'll check the overflow
+        // case in another test)
+        if n.checked_add(PAGE_SIZE - 1).is_none() {
+            return TestResult::discard()
+        }
+
+        let mut inner = InnerAlloc::new();
+
+        let layout =
+            Layout::from_size_align(n, size_of::<usize>()).expect(FROM_SIZE_ALIGN_EXPECT);
+
+        let size = layout.pad_to_align().size();
+        assert_eq!(
+            inner.alloc(layout),
+            Some(0),
+            "The given pointer for the allocation doesn't match."
+        );
+
+        let expected_alloc_start = size;
+        assert_eq!(
+            inner.next, expected_alloc_start,
+            "Our next allocation doesn't match where it should start."
+        );
+
+        let expected_limit = PAGE_SIZE * required_pages(size).unwrap();
+        assert_eq!(
+            inner.upper_limit, expected_limit,
+            "The upper bound of our heap doesn't match."
+        );
+
+        TestResult::passed()
+    }
+
+    #[quickcheck]
+    fn should_not_allocate_arbitrary_bytes_if_they_overflow(n: usize) -> TestResult {
+        // In the previous test we ignored the overflow case, now we ignore the valid cases
+        if n.checked_add(PAGE_SIZE - 1).is_some() {
+            return TestResult::discard()
+        }
+
+        if let Ok(layout) = Layout::from_size_align(n, size_of::<usize>()) {
+            let mut inner = InnerAlloc::new();
+            assert_eq!(
+                inner.alloc(layout),
+                None,
+                "An allocation which overflows the heap was made."
+            );
+
+            TestResult::passed()
+        } else {
+            // We only want to test cases which can create a valid `Layout`
+            TestResult::discard()
+        }
+    }
+
+    #[quickcheck]
+    fn should_allocate_regardless_of_alignment_size(
+        n: usize,
+        align: usize,
+    ) -> TestResult {
+        let aligns = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512];
+        let align = aligns[align % aligns.len()];
+
+        // If `n` is going to overflow we don't want to check it here (we'll check the overflow
+        // case in another test)
+        if n.checked_add(PAGE_SIZE - 1).is_none() {
+            return TestResult::discard()
+        }
+
+        let mut inner = InnerAlloc::new();
+
+        let layout = Layout::from_size_align(n, align).expect(FROM_SIZE_ALIGN_EXPECT);
+        let size = layout.pad_to_align().size();
+        assert_eq!(
+            inner.alloc(layout),
+            Some(0),
+            "The given pointer for the allocation doesn't match."
+        );
+
+        let expected_alloc_start = size;
+        assert_eq!(
+            inner.next, expected_alloc_start,
+            "Our next allocation doesn't match where it should start."
+        );
+
+        let expected_limit = PAGE_SIZE * required_pages(size).unwrap();
+        assert_eq!(
+            inner.upper_limit, expected_limit,
+            "The upper bound of our heap doesn't match."
+        );
+
+        TestResult::passed()
+    }
+
+    /// The idea behind this fuzz test is to check a series of allocation sequences. For
+    /// example, we maybe have back to back runs as follows:
+    ///
+    /// 1. `vec![1, 2, 3]`
+    /// 2. `vec![4, 5, 6, 7]`
+    /// 3. `vec![8]`
+    ///
+    /// Each of the vectors represents one sequence of allocations. Within each sequence the
+    /// individual size of allocations will be randomly selected by `quickcheck`.
+    #[quickcheck]
+    fn should_allocate_arbitrary_byte_sequences(sequence: Vec<usize>) -> TestResult {
+        let mut inner = InnerAlloc::new();
+
+        if sequence.is_empty() {
+            return TestResult::discard()
+        }
+
+        // We want to make sure no single allocation is going to overflow, we'll check this
+        // case in a different test
+        if !sequence
+            .iter()
+            .all(|n| n.checked_add(PAGE_SIZE - 1).is_some())
+        {
+            return TestResult::discard()
+        }
+
+        // We can't just use `required_pages(Iterator::sum())` here because it ends up
+        // underestimating the pages due to the ceil rounding at each step
+        let pages_required = sequence
+            .iter()
+            .fold(0, |acc, &x| acc + required_pages(x).unwrap());
+        let max_pages = required_pages(usize::MAX - PAGE_SIZE + 1).unwrap();
+
+        // We know this is going to end up overflowing, we'll check this case in a different
+        // test
+        if pages_required > max_pages {
+            return TestResult::discard()
+        }
+
+        let mut expected_alloc_start = 0;
+        let mut total_bytes_requested = 0;
+        let mut total_bytes_fragmented = 0;
+
+        for alloc in sequence {
+            let layout = Layout::from_size_align(alloc, size_of::<usize>())
+                .expect(FROM_SIZE_ALIGN_EXPECT);
+            let size = layout.pad_to_align().size();
+
+            let current_page_limit = PAGE_SIZE * required_pages(inner.next).unwrap();
+            let is_too_big_for_current_page = inner.next + size > current_page_limit;
+
+            if is_too_big_for_current_page && inner.next != 0 {
+                let fragmented_in_current_page = if current_page_limit % inner.next == 0 {
+                    current_page_limit - inner.next
+                } else {
+                    current_page_limit % inner.next
+                };
+
+                total_bytes_fragmented += fragmented_in_current_page;
+
+                // We expect our next allocation to be aligned to the start of the next page
+                // boundary
+                expected_alloc_start = inner.upper_limit;
+            }
+
+            assert_eq!(
+                inner.alloc(layout),
+                Some(expected_alloc_start),
+                "The given pointer for the allocation doesn't match."
+            );
+            total_bytes_requested += size;
+
+            expected_alloc_start = total_bytes_requested + total_bytes_fragmented;
+            assert_eq!(
+                inner.next, expected_alloc_start,
+                "Our next allocation doesn't match where it should start."
+            );
+
+            let pages_required = required_pages(expected_alloc_start).unwrap();
+            let expected_limit = PAGE_SIZE * pages_required;
+            assert_eq!(
+                inner.upper_limit, expected_limit,
+                "The upper bound of our heap doesn't match."
+            );
+        }
+
+        TestResult::passed()
+    }
+
+    // For this test we have sequences of allocations which will eventually overflow the maximum
+    // amount of pages (in practice this means our heap will be OOM).
+    //
+    // We don't care about the allocations that succeed (those are checked in other tests), we just
+    // care that eventually an allocation doesn't success.
+    #[quickcheck]
+    fn should_not_allocate_arbitrary_byte_sequences_which_eventually_overflow(
+        sequence: Vec<usize>,
+    ) -> TestResult {
+        let mut inner = InnerAlloc::new();
+
+        if sequence.is_empty() {
+            return TestResult::discard()
+        }
+
+        // We want to make sure no single allocation is going to overflow, we'll check that
+        // case seperately
+        if !sequence
+            .iter()
+            .all(|n| n.checked_add(PAGE_SIZE - 1).is_some())
+        {
+            return TestResult::discard()
+        }
+
+        // We can't just use `required_pages(Iterator::sum())` here because it ends up
+        // underestimating the pages due to the ceil rounding at each step
+        let pages_required = sequence
+            .iter()
+            .fold(0, |acc, &x| acc + required_pages(x).unwrap());
+        let max_pages = required_pages(usize::MAX - PAGE_SIZE + 1).unwrap();
+
+        // We want to explicitly test for the case where a series of allocations eventually
+        // runs out of pages of memory
+        if !(pages_required > max_pages) {
+            return TestResult::discard()
+        }
+
+        let mut results = vec![];
+        for alloc in sequence {
+            let layout = Layout::from_size_align(alloc, size_of::<usize>())
+                .expect(FROM_SIZE_ALIGN_EXPECT);
+            results.push(inner.alloc(layout));
+        }
+
+        // Ensure that at least one of the allocations ends up overflowing our calculations.
+        assert!(
+            results.iter().any(|r| r.is_none()),
+            "Expected an allocation to overflow our heap, but this didn't happen."
+        );
+
+        TestResult::passed()
+    }
+}
diff --git a/crates/allocator/src/lib.rs b/crates/allocator/src/lib.rs
index 79a427a03d..dffeb44c48 100644
--- a/crates/allocator/src/lib.rs
+++ b/crates/allocator/src/lib.rs
@@ -38,3 +38,7 @@ mod bump;
 
 #[cfg(not(feature = "std"))]
 mod handlers;
+
+#[cfg(all(test, feature = "std", feature = "ink-fuzz-tests"))]
+#[macro_use(quickcheck)]
+extern crate quickcheck_macros;
diff --git a/crates/lang/ir/src/ir/item_impl/constructor.rs b/crates/lang/ir/src/ir/item_impl/constructor.rs
index 696ec4b76b..6d32e64627 100644
--- a/crates/lang/ir/src/ir/item_impl/constructor.rs
+++ b/crates/lang/ir/src/ir/item_impl/constructor.rs
@@ -283,7 +283,7 @@ mod tests {
                 .unwrap()
                 .inputs()
                 .cloned()
-                .map(|pat_type| syn::FnArg::Typed(pat_type))
+                .map(syn::FnArg::Typed)
                 .collect::<Vec<_>>();
             assert_eq!(actual_inputs, expected_inputs);
         }
diff --git a/crates/lang/ir/src/ir/item_impl/message.rs b/crates/lang/ir/src/ir/item_impl/message.rs
index 38df9f3a88..63eda9971f 100644
--- a/crates/lang/ir/src/ir/item_impl/message.rs
+++ b/crates/lang/ir/src/ir/item_impl/message.rs
@@ -366,7 +366,7 @@ mod tests {
                 .unwrap()
                 .inputs()
                 .cloned()
-                .map(|pat_type| syn::FnArg::Typed(pat_type))
+                .map(syn::FnArg::Typed)
                 .collect::<Vec<_>>();
             assert_eq!(actual_inputs, expected_inputs);
         }
diff --git a/crates/lang/macro/Cargo.toml b/crates/lang/macro/Cargo.toml
index 691035a836..b551e3bbd5 100644
--- a/crates/lang/macro/Cargo.toml
+++ b/crates/lang/macro/Cargo.toml
@@ -44,4 +44,10 @@ std = [
     "ink_lang_ir/std",
     "ink_primitives/std",
 ]
+
+# Due to https://github.com/rust-lang/cargo/issues/6915 features that affect a dev-dependency
+# currently can't be enabled by a parent crate, hence `["ink_env/ink-experimental-engine"]` does
+# not work.
+# After we switch to the new off-chain environment with https://github.com/paritytech/ink/issues/565
+# we can remove the feature altogether.
 ink-experimental-engine = []
diff --git a/crates/primitives/benches/bench.rs b/crates/primitives/benches/bench.rs
index 60da408454..8407ea0ed5 100644
--- a/crates/primitives/benches/bench.rs
+++ b/crates/primitives/benches/bench.rs
@@ -43,7 +43,7 @@ fn bench_key_add_assign_u64(c: &mut Criterion) {
     c.bench_function("Key2::add_assign(u64)", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
-            let _ = black_box(copy += 1u64);
+            let _ = black_box(|| copy += 1u64);
         })
     });
 }
@@ -57,7 +57,7 @@ fn bench_key_add_assign_u64_one_ofvl(c: &mut Criterion) {
     c.bench_function("Key2::add_assign(u64) - 1 ofvl", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
-            let _ = black_box(copy += 1u64);
+            let _ = black_box(|| copy += 1u64);
         })
     });
 }
@@ -71,7 +71,7 @@ fn bench_key_add_assign_u64_two_ofvls(c: &mut Criterion) {
     c.bench_function("Key2::add_assign(u64) - 2 ofvls", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
-            let _ = black_box(copy += 1u64);
+            let _ = black_box(|| copy += 1u64);
         })
     });
 }
@@ -85,7 +85,7 @@ fn bench_key_add_assign_u64_three_ofvls(c: &mut Criterion) {
     c.bench_function("Key2::add_assign(u64) - 3 ofvls", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
-            let _ = black_box(copy += 1u64);
+            let _ = black_box(|| copy += 1u64);
         })
     });
 }
@@ -95,7 +95,7 @@ fn bench_key_add_assign_u64_wrap(c: &mut Criterion) {
     c.bench_function("Key2::add_assign(u64) - wrap", |b| {
         b.iter(|| {
             let mut copy = black_box(key);
-            let _ = black_box(copy += 1u64);
+            let _ = black_box(|| copy += 1u64);
         })
     });
 }
@@ -104,7 +104,7 @@ fn bench_key_ptr_advance_by(c: &mut Criterion) {
     let key = Key::from([0x00; 32]);
     c.bench_function("KeyPtr2::advance_by copy", |b| {
         b.iter(|| {
-            let mut key_ptr = KeyPtr::from(key.clone());
+            let mut key_ptr = KeyPtr::from(key);
             let _ = black_box(key_ptr.advance_by(1));
         })
     });
@@ -112,7 +112,7 @@ fn bench_key_ptr_advance_by(c: &mut Criterion) {
 
 fn bench_key_ptr_advance_by_repeat(c: &mut Criterion) {
     let key = Key::from([0x00; 32]);
-    let mut key_ptr = KeyPtr::from(key.clone());
+    let mut key_ptr = KeyPtr::from(key);
     c.bench_function("KeyPtr2::advance_by reuse", |b| {
         b.iter(|| {
             let _ = black_box(key_ptr.advance_by(1));
diff --git a/crates/storage/benches/bench_bitstash.rs b/crates/storage/benches/bench_bitstash.rs
index 1f994cbe8b..8e56875bdf 100644
--- a/crates/storage/benches/bench_bitstash.rs
+++ b/crates/storage/benches/bench_bitstash.rs
@@ -82,12 +82,10 @@ mod populated_cache {
 
 fn bench_populated_cache(c: &mut Criterion) {
     let mut group = c.benchmark_group("Bench: populated cache");
-    group.bench_function("fill_bitstash", |b| {
-        b.iter(|| populated_cache::fill_bitstash())
-    });
+    group.bench_function("fill_bitstash", |b| b.iter(populated_cache::fill_bitstash));
     group.bench_function("one_put", |b| {
         b.iter_batched_ref(
-            || create_large_stash(),
+            create_large_stash,
             |stash| one_put(stash),
             BatchSize::SmallInput,
         )
@@ -114,8 +112,7 @@ mod empty_cache {
 fn bench_empty_cache(c: &mut Criterion) {
     let _ = ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
         let mut group = c.benchmark_group("Bench: empty cache");
-        group
-            .bench_function("fill_bitstash", |b| b.iter(|| empty_cache::fill_bitstash()));
+        group.bench_function("fill_bitstash", |b| b.iter(empty_cache::fill_bitstash));
         group.bench_function("one_put", |b| {
             b.iter_batched_ref(
                 || {
diff --git a/crates/storage/benches/bench_hashmap.rs b/crates/storage/benches/bench_hashmap.rs
index 12d63268e0..a8c112c75d 100644
--- a/crates/storage/benches/bench_hashmap.rs
+++ b/crates/storage/benches/bench_hashmap.rs
@@ -131,14 +131,14 @@ macro_rules! gen_tests_for_backend {
             );
             group.bench_function("insert_and_inc", |b| {
                 b.iter_batched_ref(
-                    || setup_hashmap(),
+                    setup_hashmap,
                     |hmap| insert_and_inc(hmap),
                     BatchSize::SmallInput,
                 )
             });
             group.bench_function("insert_and_inc_entry_api", |b| {
                 b.iter_batched_ref(
-                    || setup_hashmap(),
+                    setup_hashmap,
                     |hmap| insert_and_inc_entry_api(hmap),
                     BatchSize::SmallInput,
                 )
@@ -153,14 +153,14 @@ macro_rules! gen_tests_for_backend {
                 );
                 group.bench_function("remove", |b| {
                     b.iter_batched_ref(
-                        || setup_hashmap(),
+                        setup_hashmap,
                         |hmap| remove(hmap),
                         BatchSize::SmallInput,
                     )
                 });
                 group.bench_function("remove_entry_api", |b| {
                     b.iter_batched_ref(
-                        || setup_hashmap(),
+                        setup_hashmap,
                         |hmap| remove_entry_api(hmap),
                         BatchSize::SmallInput,
                     )
diff --git a/crates/storage/benches/bench_lazy.rs b/crates/storage/benches/bench_lazy.rs
index f3747d6ce9..9a0690b659 100644
--- a/crates/storage/benches/bench_lazy.rs
+++ b/crates/storage/benches/bench_lazy.rs
@@ -39,23 +39,21 @@ mod populated_cache {
     pub fn set() {
         let mut lazy = <Lazy<i32>>::new(1);
         let lazy_mut = black_box(&mut lazy);
-        black_box(Lazy::set(lazy_mut, 17));
+        let _ = black_box(|| Lazy::set(lazy_mut, 17));
     }
 
     pub fn deref_mut() {
         let mut lazy = <Lazy<i32>>::new(1);
         let i32_mut = black_box(lazy.deref_mut());
-        black_box(*i32_mut = 17);
+        let _ = black_box(|| *i32_mut = 17);
     }
 }
 
 fn bench_set_populated_cache(c: &mut Criterion) {
     let mut group = c.benchmark_group("Compare: `set` and `deref_mut` (populated cache)");
-    group.bench_function(BenchmarkId::new("set", 0), |b| {
-        b.iter(|| populated_cache::set())
-    });
+    group.bench_function(BenchmarkId::new("set", 0), |b| b.iter(populated_cache::set));
     group.bench_function(BenchmarkId::new("deref_mut", 0), |b| {
-        b.iter(|| populated_cache::deref_mut())
+        b.iter(populated_cache::deref_mut)
     });
     group.finish();
 }
@@ -72,23 +70,21 @@ mod empty_cache {
 
     pub fn set() {
         let mut lazy = push_storage_lazy(1);
-        black_box(Lazy::set(&mut lazy, 13));
+        let _ = black_box(|| Lazy::set(&mut lazy, 13));
     }
 
     pub fn deref_mut() {
         let mut lazy = push_storage_lazy(1);
-        black_box(*lazy = 13);
+        let _ = black_box(|| *lazy = 13);
     }
 }
 
 fn bench_set_empty_cache(c: &mut Criterion) {
     let _ = ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
         let mut group = c.benchmark_group("Compare: `set` and `deref_mut` (empty cache)");
-        group.bench_function(BenchmarkId::new("set", 0), |b| {
-            b.iter(|| empty_cache::set())
-        });
+        group.bench_function(BenchmarkId::new("set", 0), |b| b.iter(empty_cache::set));
         group.bench_function(BenchmarkId::new("deref_mut", 0), |b| {
-            b.iter(|| empty_cache::deref_mut())
+            b.iter(empty_cache::deref_mut)
         });
         group.finish();
         Ok(())
diff --git a/crates/storage/benches/bench_stash.rs b/crates/storage/benches/bench_stash.rs
index eb9d3e9add..758c224506 100644
--- a/crates/storage/benches/bench_stash.rs
+++ b/crates/storage/benches/bench_stash.rs
@@ -124,9 +124,9 @@ fn bench_remove_occupied_empty_cache(c: &mut Criterion) {
             "Compare: `remove_occupied_all` and `take_all` (empty cache)",
         );
         group.bench_function("remove_occupied_all", |b| {
-            b.iter(|| empty_cache::remove_occupied_all())
+            b.iter(empty_cache::remove_occupied_all)
         });
-        group.bench_function("take_all", |b| b.iter(|| empty_cache::take_all()));
+        group.bench_function("take_all", |b| b.iter(empty_cache::take_all));
         group.finish();
         Ok(())
     })
diff --git a/crates/storage/benches/bench_vec.rs b/crates/storage/benches/bench_vec.rs
index 6322c2dd3c..943a67541f 100644
--- a/crates/storage/benches/bench_vec.rs
+++ b/crates/storage/benches/bench_vec.rs
@@ -67,26 +67,26 @@ mod populated_cache {
     use super::*;
 
     pub fn clear(test_values: &[u8]) {
-        let mut vec = storage_vec_from_slice(&test_values);
-        black_box(vec.clear());
+        let mut vec = storage_vec_from_slice(test_values);
+        let _ = black_box(|| vec.clear());
     }
 
     pub fn pop_all(test_values: &[u8]) {
-        let mut vec = storage_vec_from_slice(&test_values);
+        let mut vec = storage_vec_from_slice(test_values);
         while let Some(ignored) = black_box(vec.pop()) {
             black_box(ignored);
         }
     }
 
     pub fn set(test_values: &[u8]) {
-        let mut vec = storage_vec_from_slice(&test_values);
+        let mut vec = storage_vec_from_slice(test_values);
         for (index, _value) in test_values.iter().enumerate() {
             let _ = black_box(vec.set(index as u32, b'X'));
         }
     }
 
     pub fn get_mut(test_values: &[u8]) {
-        let mut vec = storage_vec_from_slice(&test_values);
+        let mut vec = storage_vec_from_slice(test_values);
         for (index, _value) in test_values.iter().enumerate() {
             *black_box(vec.get_mut(index as u32).unwrap()) = b'X';
         }
@@ -124,7 +124,7 @@ mod empty_cache {
     pub fn clear() {
         push_storage_vec();
         let mut vec = pull_storage_vec();
-        black_box(vec.clear());
+        let _ = black_box(|| vec.clear());
     }
 
     /// In this case we lazily load the vec from storage using `pull_spread`.
@@ -167,8 +167,8 @@ mod empty_cache {
 fn bench_clear_empty_cache(c: &mut Criterion) {
     let _ = ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
         let mut group = c.benchmark_group("Compare: `clear` and `pop_all` (empty cache)");
-        group.bench_function("clear", |b| b.iter(|| empty_cache::clear()));
-        group.bench_function("pop_all", |b| b.iter(|| empty_cache::pop_all()));
+        group.bench_function("clear", |b| b.iter(empty_cache::clear));
+        group.bench_function("pop_all", |b| b.iter(empty_cache::pop_all));
         group.finish();
         Ok(())
     })
@@ -181,8 +181,8 @@ fn bench_clear_empty_cache(c: &mut Criterion) {
 fn bench_put_empty_cache(c: &mut Criterion) {
     let _ = ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
         let mut group = c.benchmark_group("Compare: `set` and `get_mut` (empty cache)");
-        group.bench_function("set", |b| b.iter(|| empty_cache::set()));
-        group.bench_function("get_mut", |b| b.iter(|| empty_cache::get_mut()));
+        group.bench_function("set", |b| b.iter(empty_cache::set));
+        group.bench_function("get_mut", |b| b.iter(empty_cache::get_mut));
         group.finish();
         Ok(())
     })
diff --git a/crates/storage/derive/src/storage_layout.rs b/crates/storage/derive/src/storage_layout.rs
index 7ee807e090..13ee9f3c02 100644
--- a/crates/storage/derive/src/storage_layout.rs
+++ b/crates/storage/derive/src/storage_layout.rs
@@ -75,7 +75,7 @@ fn storage_layout_enum(s: &synstructure::Structure) -> TokenStream2 {
         let field_layouts = field_layout(variant);
         quote! {
             {
-                let mut __variant_key_ptr = __key_ptr.clone();
+                let mut __variant_key_ptr = *__key_ptr;
                 let mut __key_ptr = &mut __variant_key_ptr;
                 (
                     ::ink_metadata::layout::Discriminant::from(#discriminant),
diff --git a/crates/storage/src/collections/bitvec/bits256.rs b/crates/storage/src/collections/bitvec/bits256.rs
index cf1a948101..7d5ef96bb5 100644
--- a/crates/storage/src/collections/bitvec/bits256.rs
+++ b/crates/storage/src/collections/bitvec/bits256.rs
@@ -300,7 +300,7 @@ mod tests {
         for i in 0..256 {
             let i = i as u8;
             bits256.set(i);
-            assert_eq!(bits256.get(i), true);
+            assert!(bits256.get(i));
         }
     }
 
@@ -310,7 +310,7 @@ mod tests {
         for i in 0..256 {
             let i = i as u8;
             bits256.reset(i);
-            assert_eq!(bits256.get(i), false);
+            assert!(!bits256.get(i));
         }
     }
 
diff --git a/crates/storage/src/lazy/lazy_array.rs b/crates/storage/src/lazy/lazy_array.rs
index 767842027d..58494c27d1 100644
--- a/crates/storage/src/lazy/lazy_array.rs
+++ b/crates/storage/src/lazy/lazy_array.rs
@@ -558,10 +558,7 @@ mod tests {
             .iter()
             .enumerate()
             .filter_map(|(index, entry)| {
-                match entry {
-                    Some(entry) => Some((index as u32, entry)),
-                    None => None,
-                }
+                entry.as_ref().map(|entry| (index as u32, entry))
             })
             .zip(expected.iter().map(|(index, entry)| (*index, entry)))
         {
diff --git a/examples/contract-terminate/lib.rs b/examples/contract-terminate/lib.rs
index a03998cb13..e077a9d426 100644
--- a/examples/contract-terminate/lib.rs
+++ b/examples/contract-terminate/lib.rs
@@ -82,7 +82,7 @@ pub mod just_terminates {
 
         fn set_sender(sender: AccountId) {
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             test::push_execution_context::<Environment>(
                 sender,
                 callee,
diff --git a/examples/contract-transfer/lib.rs b/examples/contract-transfer/lib.rs
index 097b204ec5..ced581e846 100644
--- a/examples/contract-transfer/lib.rs
+++ b/examples/contract-transfer/lib.rs
@@ -217,7 +217,7 @@ pub mod give_me {
 
         fn set_sender(sender: AccountId) {
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             test::push_execution_context::<Environment>(
                 sender,
                 callee,
diff --git a/examples/erc1155/lib.rs b/examples/erc1155/lib.rs
index 3086fb0d17..55d42dcaf3 100644
--- a/examples/erc1155/lib.rs
+++ b/examples/erc1155/lib.rs
@@ -792,7 +792,7 @@ mod erc1155 {
             // Note: All of these tests are from the context of the owner who is either allowing or
             // disallowing an operator to control their funds.
             set_sender(owner);
-            assert!(erc.is_approved_for_all(owner, operator) == false);
+            assert!(!erc.is_approved_for_all(owner, operator));
 
             assert!(erc.set_approval_for_all(operator, true).is_ok());
             assert!(erc.is_approved_for_all(owner, operator));
@@ -801,7 +801,7 @@ mod erc1155 {
             assert!(erc.is_approved_for_all(owner, another_operator));
 
             assert!(erc.set_approval_for_all(operator, false).is_ok());
-            assert!(erc.is_approved_for_all(owner, operator) == false);
+            assert!(!erc.is_approved_for_all(owner, operator));
         }
 
         #[ink::test]
diff --git a/examples/erc20/lib.rs b/examples/erc20/lib.rs
index d237f8d0e2..1e36b51d5b 100644
--- a/examples/erc20/lib.rs
+++ b/examples/erc20/lib.rs
@@ -360,7 +360,7 @@ mod erc20 {
             assert_eq!(erc20.balance_of(accounts.bob), 0);
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -417,7 +417,7 @@ mod erc20 {
 
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call.
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -471,7 +471,7 @@ mod erc20 {
 
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call.
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -486,8 +486,7 @@ mod erc20 {
             );
 
             // Bob tries to transfer tokens from Alice to Eve.
-            let emitted_events_before =
-                ink_env::test::recorded_events().collect::<Vec<_>>();
+            let emitted_events_before = ink_env::test::recorded_events();
             assert_eq!(
                 erc20.transfer_from(accounts.alice, accounts.eve, alice_balance + 1),
                 Err(Error::InsufficientBalance)
@@ -498,9 +497,8 @@ mod erc20 {
                 initial_allowance
             );
             // No more events must have been emitted
-            let emitted_events_after =
-                ink_env::test::recorded_events().collect::<Vec<_>>();
-            assert_eq!(emitted_events_before.len(), emitted_events_after.len());
+            let emitted_events_after = ink_env::test::recorded_events();
+            assert_eq!(emitted_events_before.count(), emitted_events_after.count());
         }
     }
 
diff --git a/examples/erc721/lib.rs b/examples/erc721/lib.rs
index 4144e6fdb9..66f6a0d8df 100644
--- a/examples/erc721/lib.rs
+++ b/examples/erc721/lib.rs
@@ -525,7 +525,7 @@ mod erc721 {
             assert_eq!(erc721.owner_of(2), Some(accounts.alice));
             // Get contract address
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -557,7 +557,7 @@ mod erc721 {
             assert_eq!(erc721.approve(accounts.bob, 1), Ok(()));
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -601,13 +601,10 @@ mod erc721 {
             // Approve token Id 1 transfer for Bob on behalf of Alice.
             assert_eq!(erc721.set_approval_for_all(accounts.bob, true), Ok(()));
             // Bob is an approved operator for Alice
-            assert_eq!(
-                erc721.is_approved_for_all(accounts.alice, accounts.bob),
-                true
-            );
+            assert!(erc721.is_approved_for_all(accounts.alice, accounts.bob));
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -643,10 +640,7 @@ mod erc721 {
             // Remove operator approval for Bob on behalf of Alice.
             assert_eq!(erc721.set_approval_for_all(accounts.bob, false), Ok(()));
             // Bob is not an approved operator for Alice.
-            assert_eq!(
-                erc721.is_approved_for_all(accounts.alice, accounts.bob),
-                false
-            );
+            assert!(!erc721.is_approved_for_all(accounts.alice, accounts.bob));
         }
 
         #[ink::test]
@@ -666,7 +660,7 @@ mod erc721 {
             assert_eq!(erc721.balance_of(accounts.eve), 0);
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -737,7 +731,7 @@ mod erc721 {
 
         fn set_sender(sender: AccountId) {
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             test::push_execution_context::<Environment>(
                 sender,
                 callee,
diff --git a/examples/flipper/lib.rs b/examples/flipper/lib.rs
index 7187adcb32..7f2e76eaab 100644
--- a/examples/flipper/lib.rs
+++ b/examples/flipper/lib.rs
@@ -57,15 +57,15 @@ pub mod flipper {
         #[ink::test]
         fn default_works() {
             let flipper = Flipper::default();
-            assert_eq!(flipper.get(), false);
+            assert!(!flipper.get());
         }
 
         #[ink::test]
         fn it_works() {
             let mut flipper = Flipper::new(false);
-            assert_eq!(flipper.get(), false);
+            assert!(!flipper.get());
             flipper.flip();
-            assert_eq!(flipper.get(), true);
+            assert!(flipper.get());
         }
     }
 }
diff --git a/examples/trait-erc20/lib.rs b/examples/trait-erc20/lib.rs
index 0da0d5a99f..5be934e19a 100644
--- a/examples/trait-erc20/lib.rs
+++ b/examples/trait-erc20/lib.rs
@@ -440,7 +440,7 @@ mod erc20 {
             assert_eq!(erc20.balance_of(accounts.bob), 0);
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -497,7 +497,7 @@ mod erc20 {
 
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call.
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -551,7 +551,7 @@ mod erc20 {
 
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call.
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -566,8 +566,7 @@ mod erc20 {
             );
 
             // Bob tries to transfer tokens from Alice to Eve.
-            let emitted_events_before =
-                ink_env::test::recorded_events().collect::<Vec<_>>();
+            let emitted_events_before = ink_env::test::recorded_events();
             assert_eq!(
                 erc20.transfer_from(accounts.alice, accounts.eve, alice_balance + 1),
                 Err(Error::InsufficientBalance)
@@ -578,9 +577,8 @@ mod erc20 {
                 initial_allowance
             );
             // No more events must have been emitted
-            let emitted_events_after =
-                ink_env::test::recorded_events().collect::<Vec<_>>();
-            assert_eq!(emitted_events_before.len(), emitted_events_after.len());
+            let emitted_events_after = ink_env::test::recorded_events();
+            assert_eq!(emitted_events_before.count(), emitted_events_after.count());
         }
     }
 
diff --git a/examples/trait-flipper/lib.rs b/examples/trait-flipper/lib.rs
index bfa9aef30e..5e9dee0f05 100644
--- a/examples/trait-flipper/lib.rs
+++ b/examples/trait-flipper/lib.rs
@@ -73,17 +73,17 @@ pub mod flipper {
         #[ink::test]
         fn default_works() {
             let flipper = Flipper::default();
-            assert_eq!(flipper.get(), false);
+            assert!(!flipper.get());
         }
 
         #[ink::test]
         fn it_works() {
             let mut flipper = Flipper::new(false);
             // Can call using universal call syntax using the trait.
-            assert_eq!(<Flipper as Flip>::get(&flipper), false);
+            assert!(!<Flipper as Flip>::get(&flipper));
             <Flipper as Flip>::flip(&mut flipper);
             // Normal call syntax possible to as long as the trait is in scope.
-            assert_eq!(flipper.get(), true);
+            assert!(flipper.get());
         }
     }
 }


Test patch:
diff --git a/crates/lang/ir/src/ir/item/tests.rs b/crates/lang/ir/src/ir/item/tests.rs
index 020cc72258..515e398b1a 100644
--- a/crates/lang/ir/src/ir/item/tests.rs
+++ b/crates/lang/ir/src/ir/item/tests.rs
@@ -24,8 +24,7 @@ fn simple_storage_works() {
         }
     };
     assert!(matches!(
-        <ir::Item as TryFrom<_>>::try_from(storage_struct.clone())
-            .map_err(|err| err.to_string()),
+        <ir::Item as TryFrom<_>>::try_from(storage_struct).map_err(|err| err.to_string()),
         Ok(ir::Item::Ink(ir::InkItem::Storage(_)))
     ))
 }
@@ -41,8 +40,7 @@ fn simple_event_works() {
         }
     };
     assert!(matches!(
-        <ir::Item as TryFrom<_>>::try_from(event_struct.clone())
-            .map_err(|err| err.to_string()),
+        <ir::Item as TryFrom<_>>::try_from(event_struct).map_err(|err| err.to_string()),
         Ok(ir::Item::Ink(ir::InkItem::Event(_)))
     ))
 }
diff --git a/crates/lang/macro/tests/ui/pass/02-flipper-contract.rs b/crates/lang/macro/tests/ui/pass/02-flipper-contract.rs
index 6f3592aede..89f173cf98 100644
--- a/crates/lang/macro/tests/ui/pass/02-flipper-contract.rs
+++ b/crates/lang/macro/tests/ui/pass/02-flipper-contract.rs
@@ -37,9 +37,9 @@ mod flipper {
         #[ink::test]
         fn it_works() {
             let mut flipper = Flipper::new(false);
-            assert_eq!(flipper.get(), false);
+            assert!(!flipper.get());
             flipper.flip();
-            assert_eq!(flipper.get(), true);
+            assert!(flipper.get());
         }
     }
 }
diff --git a/crates/lang/macro/tests/ui/pass/05-erc721-contract.rs b/crates/lang/macro/tests/ui/pass/05-erc721-contract.rs
index e43a22670a..6546ca85e0 100644
--- a/crates/lang/macro/tests/ui/pass/05-erc721-contract.rs
+++ b/crates/lang/macro/tests/ui/pass/05-erc721-contract.rs
@@ -460,7 +460,7 @@ mod erc721 {
             assert_eq!(erc721.owner_of(2), Some(accounts.alice));
             // Get contract address
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -492,7 +492,7 @@ mod erc721 {
             assert_eq!(erc721.approve(accounts.bob, 1), Ok(()));
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -536,13 +536,10 @@ mod erc721 {
             // Approve token Id 1 transfer for Bob on behalf of Alice.
             assert_eq!(erc721.set_approval_for_all(accounts.bob, true), Ok(()));
             // Bob is an approved operator for Alice
-            assert_eq!(
-                erc721.is_approved_for_all(accounts.alice, accounts.bob),
-                true
-            );
+            assert!(erc721.is_approved_for_all(accounts.alice, accounts.bob));
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -578,10 +575,7 @@ mod erc721 {
             // Remove operator approval for Bob on behalf of Alice.
             assert_eq!(erc721.set_approval_for_all(accounts.bob, false), Ok(()));
             // Bob is not an approved operator for Alice.
-            assert_eq!(
-                erc721.is_approved_for_all(accounts.alice, accounts.bob),
-                false
-            );
+            assert!(!erc721.is_approved_for_all(accounts.alice, accounts.bob));
         }
 
         #[ink::test]
@@ -601,7 +595,7 @@ mod erc721 {
             assert_eq!(erc721.balance_of(accounts.eve), 0);
             // Get contract address.
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             // Create call
             let mut data =
                 ink_env::test::CallData::new(ink_env::call::Selector::new([0x00; 4])); // balance_of
@@ -672,7 +666,7 @@ mod erc721 {
 
         fn set_sender(sender: AccountId) {
             let callee = ink_env::account_id::<ink_env::DefaultEnvironment>()
-                .unwrap_or([0x0; 32].into());
+                .unwrap_or_else(|_| [0x0; 32].into());
             test::push_execution_context::<Environment>(
                 sender,
                 callee,
diff --git a/crates/lang/macro/tests/unique_topics.rs b/crates/lang/macro/tests/unique_topics.rs
index 502be60dbd..f17837ba76 100644
--- a/crates/lang/macro/tests/unique_topics.rs
+++ b/crates/lang/macro/tests/unique_topics.rs
@@ -53,12 +53,23 @@ mod my_contract {
         }
     }
 
+    impl Default for MyContract {
+        fn default() -> Self {
+            Self::new()
+        }
+    }
+
+    #[cfg(not(feature = "ink-experimental-engine"))]
     #[cfg(test)]
     mod tests {
         use super::*;
         use ink_env::test::EmittedEvent;
         use ink_lang as ink;
 
+        // The following test unfortunately has to be ignored until we make
+        // `ink-experimental-engine` the default with https://github.com/paritytech/ink/issues/565.
+        // See the issue for details.
+        #[ignore]
         #[ink::test]
         #[cfg(feature = "ink-experimental-engine")]
         fn event_must_have_unique_topics() {
@@ -81,7 +92,6 @@ mod my_contract {
         }
 
         #[ink::test]
-        #[cfg(not(feature = "ink-experimental-engine"))]
         fn event_must_have_unique_topics() {
             // given
             let my_contract = MyContract::new();
@@ -100,21 +110,21 @@ mod my_contract {
                 .collect();
             assert!(!has_duplicates(&mut encoded_topics));
         }
-    }
 
-    /// Finds duplicates in a given vector.
-    ///
-    /// This function has complexity of `O(n * log n)` and no additional memory
-    /// is required, although the order of items is not preserved.
-    fn has_duplicates<T: PartialEq + AsRef<[u8]>>(items: &mut Vec<T>) -> bool {
-        // Sort the vector
-        items.sort_by(|a, b| Ord::cmp(a.as_ref(), b.as_ref()));
-        // And then find any two consecutive equal elements.
-        items.windows(2).any(|w| {
-            match w {
-                &[ref a, ref b] => a == b,
-                _ => false,
-            }
-        })
+        /// Finds duplicates in a given vector.
+        ///
+        /// This function has complexity of `O(n * log n)` and no additional memory
+        /// is required, although the order of items is not preserved.
+        fn has_duplicates<T: PartialEq + AsRef<[u8]>>(items: &mut Vec<T>) -> bool {
+            // Sort the vector
+            items.sort_by(|a, b| Ord::cmp(a.as_ref(), b.as_ref()));
+            // And then find any two consecutive equal elements.
+            items.windows(2).any(|w| {
+                match w {
+                    [ref a, ref b] => a == b,
+                    _ => false,
+                }
+            })
+        }
     }
 }
diff --git a/crates/metadata/src/layout/tests.rs b/crates/metadata/src/layout/tests.rs
index 11d1878633..4137f63119 100644
--- a/crates/metadata/src/layout/tests.rs
+++ b/crates/metadata/src/layout/tests.rs
@@ -189,7 +189,7 @@ fn mixed_enum_layout(key_ptr: &mut KeyPtr) -> Layout {
         vec![
             (Discriminant(0), StructLayout::new(vec![])),
             {
-                let mut variant_key_ptr = key_ptr.clone();
+                let mut variant_key_ptr = *key_ptr;
                 (
                     Discriminant(1),
                     StructLayout::new(vec![
@@ -209,7 +209,7 @@ fn mixed_enum_layout(key_ptr: &mut KeyPtr) -> Layout {
                 )
             },
             {
-                let mut variant_key_ptr = key_ptr.clone();
+                let mut variant_key_ptr = *key_ptr;
                 (
                     Discriminant(2),
                     StructLayout::new(vec![
diff --git a/crates/storage/derive/src/tests/spread_layout.rs b/crates/storage/derive/src/tests/spread_layout.rs
index 1ae15a4b79..0cb9d2729b 100644
--- a/crates/storage/derive/src/tests/spread_layout.rs
+++ b/crates/storage/derive/src/tests/spread_layout.rs
@@ -12,6 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// These tests are partly testing if code is expanded correctly.
+// Hence the syntax contains a number of verbose statements which
+// are not properly cleaned up.
+#![allow(clippy::absurd_extreme_comparisons)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::match_single_binding)]
+
 use crate::spread_layout_derive;
 
 #[test]
diff --git a/crates/storage/derive/src/tests/storage_layout.rs b/crates/storage/derive/src/tests/storage_layout.rs
index a71aad91de..d52e4905ec 100644
--- a/crates/storage/derive/src/tests/storage_layout.rs
+++ b/crates/storage/derive/src/tests/storage_layout.rs
@@ -120,7 +120,7 @@ fn clike_enum_works() {
                                 ::ink_metadata::layout::LayoutKey::from(dispatch_key),
                                 vec![
                                     {
-                                        let mut __variant_key_ptr = __key_ptr.clone();
+                                        let mut __variant_key_ptr = *__key_ptr;
                                         let mut __key_ptr = &mut __variant_key_ptr;
                                         (
                                             ::ink_metadata::layout::Discriminant::from(0usize),
@@ -128,7 +128,7 @@ fn clike_enum_works() {
                                         )
                                     },
                                     {
-                                        let mut __variant_key_ptr = __key_ptr.clone();
+                                        let mut __variant_key_ptr = *__key_ptr;
                                         let mut __key_ptr = &mut __variant_key_ptr;
                                         (
                                             ::ink_metadata::layout::Discriminant::from(1usize),
@@ -136,7 +136,7 @@ fn clike_enum_works() {
                                         )
                                     },
                                     {
-                                        let mut __variant_key_ptr = __key_ptr.clone();
+                                        let mut __variant_key_ptr = *__key_ptr;
                                         let mut __key_ptr = &mut __variant_key_ptr;
                                         (
                                             ::ink_metadata::layout::Discriminant::from(2usize),
@@ -177,7 +177,7 @@ fn mixed_enum_works() {
                                 ::ink_metadata::layout::LayoutKey::from(dispatch_key),
                                 vec![
                                     {
-                                        let mut __variant_key_ptr = __key_ptr.clone();
+                                        let mut __variant_key_ptr = *__key_ptr;
                                         let mut __key_ptr = &mut __variant_key_ptr;
                                         (
                                             ::ink_metadata::layout::Discriminant::from(0usize),
@@ -185,7 +185,7 @@ fn mixed_enum_works() {
                                         )
                                     },
                                     {
-                                        let mut __variant_key_ptr = __key_ptr.clone();
+                                        let mut __variant_key_ptr = *__key_ptr;
                                         let mut __key_ptr = &mut __variant_key_ptr;
                                         (
                                             ::ink_metadata::layout::Discriminant::from(1usize),
@@ -206,7 +206,7 @@ fn mixed_enum_works() {
                                         )
                                     },
                                     {
-                                        let mut __variant_key_ptr = __key_ptr.clone();
+                                        let mut __variant_key_ptr = *__key_ptr;
                                         let mut __key_ptr = &mut __variant_key_ptr;
                                         (
                                             ::ink_metadata::layout::Discriminant::from(2usize),
diff --git a/crates/storage/src/collections/binary_heap/tests.rs b/crates/storage/src/collections/binary_heap/tests.rs
index d60a74f2ac..4280d657fd 100644
--- a/crates/storage/src/collections/binary_heap/tests.rs
+++ b/crates/storage/src/collections/binary_heap/tests.rs
@@ -152,7 +152,7 @@ fn peek_works() {
 fn peek_and_pop_works() {
     let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
     let mut sorted = data.clone();
-    sorted.sort();
+    sorted.sort_unstable();
     let mut heap = heap_from_slice(&data);
     while !heap.is_empty() {
         assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
@@ -192,7 +192,7 @@ fn min_heap_works() {
         .map(|x| Reverse::new(*x))
         .collect::<Vec<_>>();
     let mut sorted = data.clone();
-    sorted.sort();
+    sorted.sort_unstable();
     let mut heap = heap_from_slice(&data);
     while !heap.is_empty() {
         assert_eq!(heap.peek().unwrap(), sorted.last().unwrap());
@@ -518,7 +518,7 @@ fn pop_complexity_big_o_log_n() -> ink_env::Result<()> {
 fn fuzz_pop_always_returns_largest_element(xs: Vec<i32>) {
     ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
         let mut sorted = xs.clone();
-        sorted.sort();
+        sorted.sort_unstable();
         let mut heap = heap_from_slice(&xs);
 
         for x in sorted.iter().rev() {
diff --git a/crates/storage/src/collections/hashmap/fuzz_tests.rs b/crates/storage/src/collections/hashmap/fuzz_tests.rs
index 77b50344c2..52f061f426 100644
--- a/crates/storage/src/collections/hashmap/fuzz_tests.rs
+++ b/crates/storage/src/collections/hashmap/fuzz_tests.rs
@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// The fuzz tests are testing complex types.
+#![allow(clippy::type_complexity)]
+
 use super::HashMap as StorageHashMap;
 use crate::{
     test_utils::FuzzCollection,
@@ -124,7 +127,7 @@ fn fuzz_removes(xs: Vec<i32>, xth: usize) {
                 let i = xs.get(x).expect(
                     "x is always in bounds since we iterate over the vec length; qed",
                 );
-                assert_eq!(map.take(&i), Some(i.saturating_mul(10)));
+                assert_eq!(map.take(i), Some(i.saturating_mul(10)));
                 len -= 1;
             }
             assert_eq!(map.len(), len);
@@ -137,7 +140,7 @@ fn fuzz_removes(xs: Vec<i32>, xth: usize) {
                 let i = xs.get(x).expect(
                     "x is always in bounds since we iterate over the vec length; qed",
                 );
-                assert_eq!(map.get(&i), Some(&(i.saturating_mul(10))));
+                assert_eq!(map.get(i), Some(&(i.saturating_mul(10))));
             }
         }
 
diff --git a/crates/storage/src/collections/stash/tests.rs b/crates/storage/src/collections/stash/tests.rs
index fb5fc4ff9f..8335345e44 100644
--- a/crates/storage/src/collections/stash/tests.rs
+++ b/crates/storage/src/collections/stash/tests.rs
@@ -71,7 +71,7 @@ fn from_iterator_works() {
         stash
     });
     assert_eq!(stash.len(), test_values.len() as u32);
-    assert_eq!(stash.is_empty(), false);
+    assert!(!stash.is_empty());
 }
 
 #[test]
diff --git a/crates/storage/src/collections/vec/fuzz_tests.rs b/crates/storage/src/collections/vec/fuzz_tests.rs
index 3c69a6b0f6..5399aec36f 100644
--- a/crates/storage/src/collections/vec/fuzz_tests.rs
+++ b/crates/storage/src/collections/vec/fuzz_tests.rs
@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// The fuzz tests are testing complex types.
+#![allow(clippy::type_complexity)]
+
 use super::Vec as StorageVec;
 use crate::{
     test_utils::FuzzCollection,
@@ -74,7 +77,7 @@ where
     /// others intact.
     fn assign(&mut self, val: Self::Item) {
         if let Some(popped_val) = self.pop() {
-            *val = popped_val.clone();
+            *val = popped_val;
         }
     }
 }
@@ -87,11 +90,11 @@ crate::fuzz_storage!("vec_4", StorageVec<(i128, u32, bool, Option<(u32, i128)>)>
 #[quickcheck]
 fn fuzz_binary_search(mut std_vec: Vec<i32>) {
     // given
-    if std_vec.len() == 0 {
+    if std_vec.is_empty() {
         return
     }
     let original_std_vec = std_vec.clone();
-    std_vec.sort();
+    std_vec.sort_unstable();
     let ink_vec = StorageVec::from_iter(std_vec.clone());
 
     for x in original_std_vec {
@@ -115,14 +118,14 @@ fn fuzz_binary_search(mut std_vec: Vec<i32>) {
 #[quickcheck]
 fn fuzz_binary_search_nonexistent(std_vec: Vec<i32>) {
     // given
-    if std_vec.len() == 0 {
+    if std_vec.is_empty() {
         return
     }
     let mut unique_std_vec: Vec<i32> = std_vec.into_iter().unique().collect();
     let removed_el = unique_std_vec
         .pop()
         .expect("length is non-zero, first element must exist");
-    unique_std_vec.sort();
+    unique_std_vec.sort_unstable();
     let ink_vec = StorageVec::from_iter(unique_std_vec.clone());
 
     // when
@@ -144,7 +147,7 @@ fn fuzz_binary_search_nonexistent(std_vec: Vec<i32>) {
 #[quickcheck]
 fn fuzz_binary_search_by_key(mut std_vec: Vec<(i32, i32)>) {
     // given
-    if std_vec.len() == 0 {
+    if std_vec.is_empty() {
         return
     }
     let original_std_vec = std_vec.clone();
@@ -167,7 +170,7 @@ fn fuzz_binary_search_by_key(mut std_vec: Vec<(i32, i32)>) {
 #[quickcheck]
 fn fuzz_binary_search_by_key_nonexistent(std_vec: Vec<(i32, i32)>) {
     // given
-    if std_vec.len() == 0 {
+    if std_vec.is_empty() {
         return
     }
     let mut unique_std_vec: Vec<(i32, i32)> =
diff --git a/crates/storage/src/collections/vec/tests.rs b/crates/storage/src/collections/vec/tests.rs
index 541614ddb5..8f3bd7805a 100644
--- a/crates/storage/src/collections/vec/tests.rs
+++ b/crates/storage/src/collections/vec/tests.rs
@@ -460,14 +460,7 @@ fn test_binary_search() {
     assert_eq!(b.binary_search(&0), Err(0));
     assert_eq!(b.binary_search(&1), Ok(0));
     assert_eq!(b.binary_search(&2), Err(1));
-    assert!(match b.binary_search(&3) {
-        Ok(1..=3) => true,
-        _ => false,
-    });
-    assert!(match b.binary_search(&3) {
-        Ok(1..=3) => true,
-        _ => false,
-    });
+    matches!(b.binary_search(&3), Ok(1..=3));
     assert_eq!(b.binary_search(&4), Err(4));
     assert_eq!(b.binary_search(&5), Err(4));
     assert_eq!(b.binary_search(&6), Err(4));
diff --git a/crates/storage/src/test_utils.rs b/crates/storage/src/test_utils.rs
index 611f1afbad..68cbcc46eb 100644
--- a/crates/storage/src/test_utils.rs
+++ b/crates/storage/src/test_utils.rs
@@ -123,7 +123,7 @@ macro_rules! fuzz_storage {
                     // we push the generated object into storage
                     let root_key = ink_primitives::Key::from([0x42; 32]);
                     let ptr = KeyPtr::from(root_key);
-                    crate::traits::push_spread_root(&instance1, &mut root_key.clone());
+                    crate::traits::push_spread_root(&instance1, &root_key.clone());
 
                     // we pull what's in storage and assert that this is what was just pushed
                     let mut pulled: $collection_type = crate::traits::pull_spread_root(&root_key.clone());
@@ -142,8 +142,8 @@ macro_rules! fuzz_storage {
 
                     // we push the `pulled` object, on which we just executed mutations
                     // back into storage and asserts it can be pulled out intact again.
-                    crate::traits::push_spread_root(&pulled, &mut root_key.clone());
-                    let pulled2: $collection_type = crate::traits::pull_spread_root(&mut root_key.clone());
+                    crate::traits::push_spread_root(&pulled, &root_key.clone());
+                    let pulled2: $collection_type = crate::traits::pull_spread_root(&root_key.clone());
                     assert_eq!(pulled, pulled2);
 
                     // we clear the objects from storage and assert that everything was
@@ -169,7 +169,7 @@ macro_rules! fuzz_storage {
                     // we push the generated object into storage
                     let root_key = ink_primitives::Key::from([0x42; 32]);
                     let ptr = KeyPtr::from(root_key);
-                    crate::traits::push_spread_root(&instance1, &mut root_key.clone());
+                    crate::traits::push_spread_root(&instance1, &root_key.clone());
 
                     // we pull what's in storage and assert that this is what was just pushed
                     let mut pulled: $collection_type = crate::traits::pull_spread_root(&root_key.clone());
@@ -181,8 +181,8 @@ macro_rules! fuzz_storage {
                     // we push the `pulled` object, on which we just executed mutations
                     // back into storage and assert it can be pulled out intact again and
                     // is equal to `instance2`.
-                    crate::traits::push_spread_root(&pulled, &mut root_key.clone());
-                    let pulled2: $collection_type = crate::traits::pull_spread_root(&mut root_key.clone());
+                    crate::traits::push_spread_root(&pulled, &root_key.clone());
+                    let pulled2: $collection_type = crate::traits::pull_spread_root(&root_key.clone());
                     assert_eq!(pulled, pulled2);
                     assert_eq!(pulled2, instance2);