diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs
index aa668f29..7bb87e14 100644
--- a/helix-core/src/auto_pairs.rs
+++ b/helix-core/src/auto_pairs.rs
@@ -24,6 +24,7 @@ const CLOSE_BEFORE: &str = ")]}'\":;> \n"; // includes space and newline
 
 // TODO: delete implementation where it erases the whole bracket (|) -> |
 
+#[must_use]
 pub fn hook(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> {
     for &(open, close) in PAIRS {
         if open == ch {
diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs
index 5bcf3767..c3b91b4f 100644
--- a/helix-core/src/comment.rs
+++ b/helix-core/src/comment.rs
@@ -37,6 +37,7 @@ fn find_line_comment(
     (commented, skipped, min)
 }
 
+#[must_use]
 pub fn toggle_line_comments(doc: &Rope, selection: &Selection) -> Transaction {
     let text = doc.slice(..);
     let mut changes: Vec<Change> = Vec::new();
diff --git a/helix-core/src/graphemes.rs b/helix-core/src/graphemes.rs
index e436062a..5ec95615 100644
--- a/helix-core/src/graphemes.rs
+++ b/helix-core/src/graphemes.rs
@@ -3,6 +3,7 @@ use ropey::{iter::Chunks, str_utils::byte_to_char_idx, RopeSlice};
 use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
 use unicode_width::UnicodeWidthStr;
 
+#[must_use]
 pub fn grapheme_width(g: &str) -> usize {
     if g.as_bytes()[0] <= 127 {
         // Fast-path ascii.
@@ -26,6 +27,7 @@ pub fn grapheme_width(g: &str) -> usize {
     }
 }
 
+#[must_use]
 pub fn nth_prev_grapheme_boundary(slice: RopeSlice, char_idx: usize, n: usize) -> usize {
     // Bounds check
     debug_assert!(char_idx <= slice.len_chars());
@@ -71,6 +73,7 @@ pub fn prev_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> usize {
     nth_prev_grapheme_boundary(slice, char_idx, 1)
 }
 
+#[must_use]
 pub fn nth_next_grapheme_boundary(slice: RopeSlice, char_idx: usize, n: usize) -> usize {
     // Bounds check
     debug_assert!(char_idx <= slice.len_chars());
@@ -138,12 +141,12 @@ pub fn is_grapheme_boundary(slice: RopeSlice, char_idx: usize) -> bool {
                 let (ctx_chunk, ctx_byte_start, _, _) = slice.chunk_at_byte(n - 1);
                 gc.provide_context(ctx_chunk, ctx_byte_start);
             }
-            _ => unreachable!(),
+            Err(_) => unreachable!(),
         }
     }
 }
 
-/// An iterator over the graphemes of a RopeSlice.
+/// An iterator over the graphemes of a `RopeSlice`.
 #[derive(Clone)]
 pub struct RopeGraphemes<'a> {
     text: RopeSlice<'a>,
@@ -154,6 +157,7 @@ pub struct RopeGraphemes<'a> {
 }
 
 impl<'a> RopeGraphemes<'a> {
+    #[must_use]
     pub fn new(slice: RopeSlice) -> RopeGraphemes {
         let mut chunks = slice.chunks();
         let first_chunk = chunks.next().unwrap_or("");
diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs
index c92c2a89..13a2a020 100644
--- a/helix-core/src/history.rs
+++ b/helix-core/src/history.rs
@@ -53,7 +53,7 @@ impl History {
     }
 
     #[inline]
-    pub fn at_root(&self) -> bool {
+    pub const fn at_root(&self) -> bool {
         self.cursor == 0
     }
 
diff --git a/helix-core/src/match_brackets.rs b/helix-core/src/match_brackets.rs
index bacd764f..f641d094 100644
--- a/helix-core/src/match_brackets.rs
+++ b/helix-core/src/match_brackets.rs
@@ -3,6 +3,7 @@ use crate::{Range, Rope, Selection, Syntax};
 // const PAIRS: &[(char, char)] = &[('(', ')'), ('{', '}'), ('[', ']')];
 // limit matching pairs to only ( ) { } [ ] < >
 
+#[must_use]
 pub fn find(syntax: &Syntax, doc: &Rope, pos: usize) -> Option<usize> {
     let tree = syntax.root_layer.tree.as_ref().unwrap();
 
diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs
index 346779b0..3d85ff2f 100644
--- a/helix-core/src/position.rs
+++ b/helix-core/src/position.rs
@@ -37,7 +37,7 @@ impl Position {
 
 impl From<(usize, usize)> for Position {
     fn from(tuple: (usize, usize)) -> Self {
-        Position {
+        Self {
             row: tuple.0,
             col: tuple.1,
         }
diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs
index e16c2b6d..e76e12b4 100644
--- a/helix-core/src/selection.rs
+++ b/helix-core/src/selection.rs
@@ -99,14 +99,14 @@ impl Range {
     #[must_use]
     pub fn extend(&self, from: usize, to: usize) -> Self {
         if from <= self.anchor && to >= self.anchor {
-            return Range {
+            return Self {
                 anchor: from,
                 head: to,
                 horiz: None,
             };
         }
 
-        Range {
+        Self {
             anchor: self.anchor,
             head: if abs_difference(from, self.anchor) > abs_difference(to, self.anchor) {
                 from
@@ -253,7 +253,7 @@ impl Selection {
 
         // fast path for a single selection (cursor)
         if ranges.len() == 1 {
-            return Selection {
+            return Self {
                 ranges,
                 primary_index: 0,
             };
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs
index 63e39f8f..3640e0cf 100644
--- a/helix-core/src/syntax.rs
+++ b/helix-core/src/syntax.rs
@@ -66,10 +66,10 @@ impl LanguageConfiguration {
                         language,
                         &highlights_query,
                         &injections_query,
-                        &locals_query,
+                        locals_query,
                     )
                     .unwrap(); // TODO: no unwrap
-                    config.configure(&scopes);
+                    config.configure(scopes);
                     Some(Arc::new(config))
                 }
             })
@@ -90,8 +90,8 @@ pub struct Loader {
 }
 
 impl Loader {
-    fn init() -> Loader {
-        let mut loader = Loader {
+    fn init() -> Self {
+        let mut loader = Self {
             language_configs: Vec::new(),
             language_config_ids_by_file_type: HashMap::new(),
         };
@@ -331,7 +331,7 @@ impl Syntax {
 
         let mut result = HighlightIter {
             source,
-            byte_offset: range.map(|r| r.start).unwrap_or(0), // TODO: simplify
+            byte_offset: range.map_or(0, |r| r.start), // TODO: simplify
             injection_callback,
             cancellation_flag,
             iter_count: 0,
@@ -1019,12 +1019,12 @@ impl<'a> HighlightIterLayer<'a> {
 
             if queue.is_empty() {
                 break;
-            } else {
-                let (next_config, next_depth, next_ranges) = queue.remove(0);
-                config = next_config;
-                depth = next_depth;
-                ranges = next_ranges;
             }
+
+            let (next_config, next_depth, next_ranges) = queue.remove(0);
+            config = next_config;
+            depth = next_depth;
+            ranges = next_ranges;
         }
 
         Ok(result)
@@ -1292,7 +1292,7 @@ where
             // If this capture represents an injection, then process the injection.
             if match_.pattern_index < layer.config.locals_pattern_index {
                 let (language_name, content_node, include_children) =
-                    injection_for_match(&layer.config, &layer.config.query, &match_, self.source);
+                    injection_for_match(layer.config, &layer.config.query, &match_, self.source);
 
                 // Explicitly remove this match so that none of its other captures will remain
                 // in the stream of captures.
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs
index d707016b..aaf912dd 100644
--- a/helix-core/src/transaction.rs
+++ b/helix-core/src/transaction.rs
@@ -84,11 +84,7 @@ impl ChangeSet {
         }
 
         let new_last = match self.changes.as_mut_slice() {
-            [.., Insert(prev)] => {
-                prev.push_tendril(&fragment);
-                return;
-            }
-            [.., Insert(prev), Delete(_)] => {
+            [.., Insert(prev)] | [.., Insert(prev), Delete(_)] => {
                 prev.push_tendril(&fragment);
                 return;
             }
@@ -115,7 +111,7 @@ impl ChangeSet {
     /// Combine two changesets together.
     /// In other words,  If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
     /// returned value will represent the change `docA` → `docC`.
-    pub fn compose(self, other: ChangeSet) -> Self {
+    pub fn compose(self, other: Self) -> Self {
         debug_assert!(self.len_after() == other.len);
 
         let len = self.changes.len();
diff --git a/helix-syntax/build.rs b/helix-syntax/build.rs
index f08a8819..ecf33dfe 100644
--- a/helix-syntax/build.rs
+++ b/helix-syntax/build.rs
@@ -11,7 +11,7 @@ fn get_debug() -> bool {
     env::var("DEBUG").unwrap() == "true"
 }
 
-fn collect_tree_sitter_dirs(ignore: Vec<String>) -> Vec<String> {
+fn collect_tree_sitter_dirs(ignore: &[String]) -> Vec<String> {
     let mut dirs = Vec::new();
     for entry in fs::read_dir("languages").unwrap().flatten() {
         let path = entry.path();
@@ -97,12 +97,12 @@ fn build_dir(dir: &str, language: &str) {
         eprintln!("You can fix in using 'git submodule init && git submodule update --recursive'.");
         std::process::exit(1);
     }
-    let (c, cpp) = collect_src_files(&dir);
+    let (c, cpp) = collect_src_files(dir);
     if !c.is_empty() {
-        build_c(c, &language);
+        build_c(c, language);
     }
     if !cpp.is_empty() {
-        build_cpp(cpp, &language);
+        build_cpp(cpp, language);
     }
 }
 
@@ -111,7 +111,7 @@ fn main() {
         "tree-sitter-typescript".to_string(),
         "tree-sitter-cpp".to_string(),
     ];
-    let dirs = collect_tree_sitter_dirs(ignore);
+    let dirs = collect_tree_sitter_dirs(&ignore);
 
     let mut n_jobs = 0;
     let pool = threadpool::Builder::new().build(); // by going through the builder, it'll use num_cpus
@@ -123,7 +123,7 @@ fn main() {
 
         pool.execute(move || {
             let language = &dir[12..]; // skip tree-sitter- prefix
-            build_dir(&dir, &language);
+            build_dir(&dir, language);
 
             // report progress
             tx.send(1).unwrap();