From 6a64eb0f3a99b0f4c1173c5ac7a4ab2a6ea92e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20S=C3=A1=20de=20Mello?= Date: Sun, 26 Jul 2026 12:04:50 +0100 Subject: [PATCH] Resolve all clippy and rustc lint warnings across the feature powerset Clean bill of lints with no public API changes: - Fix the `clippy::all`/`clippy::pedantic` errors: an `explicit_auto_deref` in `StringOrToken::read_span`, redundant `.into_iter()` and `String::from("")` in tests, and bare URLs in the README (included as crate docs). - Make elided output lifetimes explicit in `pointer.rs` public signatures (`Tokens<'_>`, `Token<'_>`, `Components<'_>`), silencing the newer `mismatched_lifetime_syntaxes` lint. Purely syntactic; no API change. - Drop the blanket `#[macro_use] extern crate alloc`, which was unused in the minimal feature set. Import `vec!`/`format!` where used instead (inline for single-use sites, matching the existing style). - Gate feature-only items so they don't warn as dead code when their consumer features are off: `Assigned` (json/toml), and `parse_index` plus its `Token` import (json). Verified clean with `cargo hack --feature-powerset clippy` and `cargo clippy --all-features --all-targets`. Preserves the intent of the `default_lifetime_is_correct` regression test (kept `unwrap_or_default`, with a local `#[allow]`, rather than letting clippy --fix reduce it away). Claude-Session: https://claude.ai/code/session_01XGvHsB4a2dxDVUQDGBScnW --- CHANGELOG.md | 7 +++++++ README.md | 4 ++-- src/assign.rs | 7 ++++++- src/index.rs | 18 ++++++------------ src/lib.rs | 1 - src/pointer.rs | 24 ++++++++++++++---------- src/resolve.rs | 7 ++++++- src/token.rs | 21 ++++++--------------- 8 files changed, 47 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fc909f..408392d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Resolved all `clippy` (`clippy::all` + `clippy::pedantic`) and `rustc` lint + warnings across the full feature powerset — including newer-toolchain lints + (`mismatched_lifetime_syntaxes`) and feature-combination dead-code warnings. + Internal only; no public API changes. + ## [0.8.0] 2026-07-26 ### Added diff --git a/README.md b/README.md index c03f640..700131e 100644 --- a/README.md +++ b/README.md @@ -186,9 +186,9 @@ In the case of [`PointerBuf::parse`], the [`ParseError`] is always wrapped in a Licensed under either of - Apache License, Version 2.0 - ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + ([LICENSE-APACHE](LICENSE-APACHE) or ) - MIT license - ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + ([LICENSE-MIT](LICENSE-MIT) or ) at your convenience. diff --git a/src/assign.rs b/src/assign.rs index 870e4b2..126a868 100644 --- a/src/assign.rs +++ b/src/assign.rs @@ -216,6 +216,7 @@ impl Diagnostic for Error { } fn labels(&self, origin: &Self::Subject) -> Option>> { + use alloc::format; let position = self.position(); let token = origin.get(position)?; let offset = if self.offset() + 1 < origin.as_str().len() { @@ -264,6 +265,7 @@ mod json { use serde_json::{map::Entry, Map, Value}; fn expand(mut remaining: &Pointer, mut value: Value) -> Value { + use alloc::vec; while let Some((ptr, tok)) = remaining.split_back() { remaining = ptr; match tok.encoded() { @@ -430,11 +432,12 @@ mod json { mod toml { use super::{Assign, Assigned, Error}; use crate::{Pointer, Token}; - use alloc::{string::String, vec, vec::Vec}; + use alloc::{string::String, vec::Vec}; use core::mem; use toml::{map::Entry, map::Map, Value}; fn expand(mut remaining: &Pointer, mut value: Value) -> Value { + use alloc::vec; while let Some((ptr, tok)) = remaining.split_back() { remaining = ptr; match tok.encoded() { @@ -595,6 +598,8 @@ mod toml { } } +// `Assigned` is only referenced by the `json` and `toml` assignment impls. +#[cfg(any(feature = "json", feature = "toml"))] enum Assigned<'v, V> { Done(Option), Continue { next_dest: &'v mut V, same_value: V }, diff --git a/src/index.rs b/src/index.rs index c1ebf4c..3862c86 100644 --- a/src/index.rs +++ b/src/index.rs @@ -350,7 +350,7 @@ impl miette::SourceCode for StringOrToken { context_lines_before: usize, context_lines_after: usize, ) -> Result + 'a>, miette::MietteError> { - let s: &str = &**self; + let s: &str = self; s.read_span(span, context_lines_before, context_lines_after) } } @@ -552,10 +552,7 @@ mod tests { #[cfg(feature = "miette")] { - let labels: Vec<_> = miette::Diagnostic::labels(&err) - .unwrap() - .into_iter() - .collect(); + let labels: Vec<_> = miette::Diagnostic::labels(&err).unwrap().collect(); assert_eq!( labels, vec![miette::LabeledSpan::new( @@ -567,7 +564,7 @@ mod tests { } let (src, sub) = err.decompose(); - let labels: Vec<_> = src.labels(&sub).unwrap().into_iter().collect(); + let labels: Vec<_> = src.labels(&sub).unwrap().collect(); assert_eq!( labels, @@ -582,10 +579,7 @@ mod tests { #[cfg(feature = "miette")] { - let labels: Vec<_> = miette::Diagnostic::labels(&err) - .unwrap() - .into_iter() - .collect(); + let labels: Vec<_> = miette::Diagnostic::labels(&err).unwrap().collect(); assert_eq!( labels, vec![miette::LabeledSpan::new(Some("leading zeros".into()), 0, 5)] @@ -593,14 +587,14 @@ mod tests { } let (src, sub) = err.decompose(); - let labels: Vec<_> = src.labels(&sub).unwrap().into_iter().collect(); + let labels: Vec<_> = src.labels(&sub).unwrap().collect(); assert_eq!(labels, vec![Label::new("leading zeros".into(), 0, 5)]); } #[test] fn error_from_empty_string() { - let s = String::from(""); + let s = String::new(); let err = Index::try_from(&s).diagnose(s).unwrap_err(); #[cfg(feature = "miette")] diff --git a/src/lib.rs b/src/lib.rs index 1339c83..8200bd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,6 @@ clippy::similar_names )] -#[cfg_attr(not(feature = "std"), macro_use)] extern crate alloc; #[cfg(feature = "assign")] diff --git a/src/pointer.rs b/src/pointer.rs index a2714e6..003d5ea 100644 --- a/src/pointer.rs +++ b/src/pointer.rs @@ -117,7 +117,7 @@ impl Pointer { } /// Returns an iterator of `Token`s in the `Pointer`. - pub fn tokens(&self) -> Tokens { + pub fn tokens(&self) -> Tokens<'_> { let mut s = self.0.split('/'); // skipping the first '/' s.next(); @@ -141,7 +141,7 @@ impl Pointer { } /// Returns the last `Token` in the `Pointer`. - pub fn back(&self) -> Option { + pub fn back(&self) -> Option> { self.0 .rsplit_once('/') // SAFETY: pointer is encoded @@ -151,12 +151,12 @@ impl Pointer { /// Returns the last token in the `Pointer`. /// /// alias for `back` - pub fn last(&self) -> Option { + pub fn last(&self) -> Option> { self.back() } /// Returns the first `Token` in the `Pointer`. - pub fn front(&self) -> Option { + pub fn front(&self) -> Option> { if self.is_root() { return None; } @@ -173,12 +173,12 @@ impl Pointer { /// Returns the first `Token` in the `Pointer`. /// /// alias for `front` - pub fn first(&self) -> Option { + pub fn first(&self) -> Option> { self.front() } /// Splits the `Pointer` into the first `Token` and a remainder `Pointer`. - pub fn split_front(&self) -> Option<(Token, &Self)> { + pub fn split_front(&self) -> Option<(Token<'_>, &Self)> { if self.is_root() { return None; } @@ -255,7 +255,7 @@ impl Pointer { } /// Splits the `Pointer` into the parent path and the last `Token`. - pub fn split_back(&self) -> Option<(&Self, Token)> { + pub fn split_back(&self) -> Option<(&Self, Token<'_>)> { self.0.rsplit_once('/').map(|(front, back)| { ( // SAFETY: we split at a token boundary, so front is a valid pointer @@ -503,7 +503,7 @@ impl Pointer { /// assert_eq!(components.next(), Some(Component::Token("b".into()))); /// assert_eq!(components.next(), None); /// ``` - pub fn components(&self) -> Components { + pub fn components(&self) -> Components<'_> { self.into() } @@ -640,6 +640,7 @@ impl<'de: 'p, 'p> serde::Deserialize<'de> for &'p Pointer { where E: Error, { + use alloc::format; Pointer::parse(v).map_err(|err| { Error::custom(format!("failed to parse json pointer\n\ncaused by:\n{err}")) }) @@ -1022,7 +1023,7 @@ impl PointerBuf { &mut self, index: usize, token: impl Into>, - ) -> Result, ReplaceError> { + ) -> Result>, ReplaceError> { if self.is_root() { return Err(ReplaceError { count: self.count(), @@ -2380,7 +2381,10 @@ mod tests { #[test] fn default_lifetime_is_correct() { - // if this compiles, we're good + // if this compiles, we're good: `unwrap_or_default` exercises + // `<&Pointer as Default>::default()` and must type-check with the + // borrowed lifetime (regression test for #111). + #[allow(clippy::unnecessary_literal_unwrap)] fn or_default(ptr: &Pointer) -> &Pointer { Some(ptr).unwrap_or_default() } diff --git a/src/resolve.rs b/src/resolve.rs index e453ee8..3cf6ff4 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -36,8 +36,11 @@ use crate::{ diagnostic::{diagnostic_url, Diagnostic, Label}, index::{OutOfBoundsError, ParseIndexError}, - Pointer, PointerBuf, Token, + Pointer, PointerBuf, }; +// `Token` is only referenced by the `json`-gated `parse_index`. +#[cfg(feature = "json")] +use crate::Token; use alloc::{boxed::Box, string::ToString}; use core::iter::once; @@ -344,6 +347,8 @@ mod json { } } } +// `parse_index` is only referenced by the `json` resolve impl. +#[cfg(feature = "json")] fn parse_index( token: Token, array_len: usize, diff --git a/src/token.rs b/src/token.rs index 94298ba..2a4f801 100644 --- a/src/token.rs +++ b/src/token.rs @@ -510,15 +510,12 @@ mod tests { let sub = String::from("a/b"); let err = Token::from_encoded(&sub).unwrap_err(); - let labels: Vec<_> = err.labels(&sub).unwrap().into_iter().collect(); + let labels: Vec<_> = err.labels(&sub).unwrap().collect(); assert_eq!(labels, vec![Label::new("invalid character".into(), 1, 1)]); let err = err.into_report(sub); #[cfg(feature = "miette")] { - let labels: Vec<_> = miette::Diagnostic::labels(&err) - .unwrap() - .into_iter() - .collect(); + let labels: Vec<_> = miette::Diagnostic::labels(&err).unwrap().collect(); assert_eq!( labels, vec![miette::LabeledSpan::new( @@ -539,15 +536,12 @@ mod tests { let sub = String::from("a~a"); let err = Token::from_encoded(&sub).unwrap_err(); - let labels: Vec<_> = err.labels(&sub).unwrap().into_iter().collect(); + let labels: Vec<_> = err.labels(&sub).unwrap().collect(); assert_eq!(labels, vec![Label::new("must be 0 or 1".into(), 2, 1)]); let err = err.into_report(sub); #[cfg(feature = "miette")] { - let labels: Vec<_> = miette::Diagnostic::labels(&err) - .unwrap() - .into_iter() - .collect(); + let labels: Vec<_> = miette::Diagnostic::labels(&err).unwrap().collect(); assert_eq!( labels, vec![miette::LabeledSpan::new( @@ -567,7 +561,7 @@ mod tests { ); let sub = String::from("a~"); let err = Token::from_encoded(&sub).unwrap_err(); - let labels: Vec<_> = err.labels(&sub).unwrap().into_iter().collect(); + let labels: Vec<_> = err.labels(&sub).unwrap().collect(); assert_eq!( labels, vec![Label::new("incomplete escape sequence".into(), 1, 1)] @@ -575,10 +569,7 @@ mod tests { let err = err.into_report(sub); #[cfg(feature = "miette")] { - let labels: Vec<_> = miette::Diagnostic::labels(&err) - .unwrap() - .into_iter() - .collect(); + let labels: Vec<_> = miette::Diagnostic::labels(&err).unwrap().collect(); assert_eq!( labels, vec![miette::LabeledSpan::new(