Skip to content

Add some clippy lints#7755

Merged
youknowone merged 15 commits into
RustPython:mainfrom
ShaharNaveh:more-clippy-lints
May 2, 2026
Merged

Add some clippy lints#7755
youknowone merged 15 commits into
RustPython:mainfrom
ShaharNaveh:more-clippy-lints

Conversation

@ShaharNaveh
Copy link
Copy Markdown
Contributor

@ShaharNaveh ShaharNaveh commented May 1, 2026

Summary by CodeRabbit

  • Chores

    • Added more Clippy lint rules.
    • Replaced eager default/error constructions with lazy variants to reduce unnecessary allocations.
  • Refactor

    • Reduced redundant cloning by moving values where possible.
    • Consolidated and simplified pattern matching across many modules, preserving existing behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds nine Clippy lints to workspace config and performs widespread micro-refactors: consolidates match patterns, replaces eager fallbacks with lazy closures, and eliminates redundant clones across many crates without changing public APIs or core control flow.

Changes

Cohort / File(s) Summary
Clippy Configuration
Cargo.toml
Added nine new Clippy lint rules under [workspace.lints.clippy] at warning level.
Codegen
crates/codegen/src/compile.rs, crates/codegen/src/ir.rs, crates/codegen/src/symboltable.rs
Grouped/combined match patterns and moved ownership instead of cloning in several places; minor test/assert pattern formatting.
Common: formatting & strings
crates/common/src/format.rs, crates/common/src/str.rs
Consolidated match arms and changed eager defaults (unwrap_or) to lazy closures (unwrap_or_else) in formatting and zfill logic.
Derive macros
crates/derive-impl/src/pyclass.rs, crates/derive-impl/src/pystructseq.rs
Combined match arms and consumed structs in-place (avoiding clones) for macro generation.
Stdlib (various modules)
crates/stdlib/src/_asyncio.rs, .../contextvars.rs, .../csv.rs, .../mmap.rs, .../socket.rs, .../ssl.rs, .../ssl/cert.rs, .../ssl/compat.rs, .../unicodedata.rs
Removed redundant clones, consolidated patterns, made default constructions lazy, and tightened some OS/path error handling.
VM builtins & core
crates/vm/src/builtins/..., crates/vm/src/codecs.rs, crates/vm/src/exception_group.rs, crates/vm/src/exceptions.rs
Moved values instead of cloning, used lazy default/error construction, and simplified pattern matches; added a Clippy expect in one site.
VM internals & utilities
crates/vm/src/frame.rs, crates/vm/src/buffer.rs, crates/vm/src/getpath.rs, crates/vm/src/import.rs, crates/vm/src/ospath.rs
Optimized ownership (move vs clone), accepted additional endianness marker, and made several fallbacks lazy.
_ctypes family
crates/vm/src/stdlib/_ctypes.rs, .../array.rs, .../base.rs, .../function.rs, .../pointer.rs, .../simple.rs, .../structure.rs, .../union.rs
Consolidated PEP‑3118/type-code patterns, removed redundant clones, made error/default creation lazy, simplified read/write helpers, and adjusted ownership.
Misc stdlib & VM modules
crates/vm/src/stdlib/_abc.rs, .../_ast/python.rs, .../_io.rs, .../_sre.rs, .../_sysconfigdata.rs, .../_thread.rs, crates/vm/src/stdlib/builtins.rs, .../itertools.rs, .../sys.rs, .../time.rs, .../types/structseq.rs, crates/vm/src/vm/mod.rs, crates/vm/src/warn.rs
Eliminated extra clones, switched eager constructions to lazy closures, and streamlined internal initializer/lookup paths without changing public APIs.

Sequence Diagram(s)

(Skipped — changes are refactors/ownership and do not introduce new multi-component control flows.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • youknowone
  • coolreader18

Poem

🐇
I munched the clones, I paired the match,
Closed lazy doors with a tiny latch,
I moved the bits where they should be,
Tidied patterns for all to see,
The repo hops on — light-footed and spry.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add some clippy lints' accurately describes the primary change in the changeset, which is adding nine new Clippy lint configuration rules to Cargo.toml.
Docstring Coverage ✅ Passed Docstring coverage is 91.96% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
crates/vm/src/ospath.rs (1)

128-135: ⚡ Quick win

Consider removing the clone here for consistency.

Similar to the optimization on line 113, the clone on line 128 can be eliminated by using the PyObjectRef returned from the Err variant.

♻️ Proposed refactor
-        self.try_match_str_bytes(result.clone(), vm)?.map_err(|_| {
+        self.try_match_str_bytes(result, vm)?.map_err(|result_obj| {
             vm.new_type_error(format!(
                 "{}expected {}.__fspath__() to return str or bytes, not {}",
                 self.error_prefix(),
                 obj.class().name(),
-                result.class().name(),
+                result_obj.class().name(),
             ))
         })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm/src/ospath.rs` around lines 128 - 135, The clone of result is
unnecessary: remove the .clone() passed to self.try_match_str_bytes and instead
capture the Err value inside map_err’s closure (e.g., .map_err(|obj| { ... }))
so you can use that PyObjectRef’s class name in the error message (use
obj.class().name() instead of result.class().name()); update the closure
parameter name accordingly while keeping vm.new_type_error and the existing
format string.
crates/stdlib/src/csv.rs (1)

98-99: Pass string literals and char values directly to new_str instead of allocating unnecessarily.

The new_str method accepts impl Into<pystr::PyStr>, which includes &str and char. Line 98 can pass the string literal directly without .to_string(). For line 99, since t is a u8, cast it to char and pass it directly instead of using format!.

Suggested changes
                Terminator::CRLF => vm.ctx.new_str("\r\n"),
                Terminator::Any(t) => vm.ctx.new_str(t as char),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/stdlib/src/csv.rs` around lines 98 - 99, In crates/stdlib/src/csv.rs,
the Terminator match allocates unnecessarily by calling .to_string() and
format!; update the Terminator::CRLF and Terminator::Any arms to pass literals
and char values directly into vm.ctx.new_str (use the string literal "\r\n" and
cast the u8 t to char) so new_str receives &str/char instead of an owned String,
eliminating the extra allocations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/stdlib/src/csv.rs`:
- Around line 1028-1030: Replace the redundant and panicking UTF-8 conversion by
using the already-validated string `s`: instead of calling
String::from_utf8(...).unwrap().parse::<i64>(), trim and parse the slice of `s`
(e.g., `s[range].trim().parse::<i64>()`) and match on the parse Result (e.g.,
`if let Ok(t) = ...`) so you never call `.unwrap()`; ensure you drop the extra
conversion of `buffer` and only operate on `s`, keeping error handling via the
parse result.

In `@crates/vm/src/format.rs`:
- Around line 59-61: The loop is pushing a libc::c_char into a Vec<u8> causing
portability/compile issues on platforms where c_char = i8; update the push to
cast the dereferenced pointer to the Vec element type using a generic cast (use
as _) so the compiler infers the correct unsigned type—i.e., change the use of
result.push(*ptr) to result.push(*ptr as _) and keep the existing sentinel check
using libc::c_char::MAX; this touches the variables result and ptr in the loop
in format.rs.

In `@crates/vm/src/stdlib/_ctypes/function.rs`:
- Around line 2111-2119: The current match arm incorrectly groups "l"/"L" with
"q"/"Q" and always writes 8-byte i64/u64 values, causing buffer overruns on
32-bit targets; update the match in the callback writer so "l" and "L" are
handled separately from "q"/"Q": for "l" write into the result as the
platform-dependent c_long type (use the module's c_long type and convert the
BigInt to an i64 then cast to c_long with a safe fallback), for "L" write as
c_ulong (convert via to_u64 then cast to c_ulong with fallback), and keep
"q"/"Q" writing i64/u64 as before; reference the existing match arms for ("l" |
"q"), ("L" | "Q"), get_ffi_type, and the result pointer handling so you change
the pointer casts to *mut c_long/*mut c_ulong for "l"/"L" respectively instead
of *mut i64/*mut u64.

---

Nitpick comments:
In `@crates/stdlib/src/csv.rs`:
- Around line 98-99: In crates/stdlib/src/csv.rs, the Terminator match allocates
unnecessarily by calling .to_string() and format!; update the Terminator::CRLF
and Terminator::Any arms to pass literals and char values directly into
vm.ctx.new_str (use the string literal "\r\n" and cast the u8 t to char) so
new_str receives &str/char instead of an owned String, eliminating the extra
allocations.

In `@crates/vm/src/ospath.rs`:
- Around line 128-135: The clone of result is unnecessary: remove the .clone()
passed to self.try_match_str_bytes and instead capture the Err value inside
map_err’s closure (e.g., .map_err(|obj| { ... })) so you can use that
PyObjectRef’s class name in the error message (use obj.class().name() instead of
result.class().name()); update the closure parameter name accordingly while
keeping vm.new_type_error and the existing format string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 03445c0b-9f46-44f5-90bd-ab60824e0bf5

📥 Commits

Reviewing files that changed from the base of the PR and between d25195e and 499a344.

📒 Files selected for processing (55)
  • Cargo.toml
  • crates/codegen/src/compile.rs
  • crates/codegen/src/ir.rs
  • crates/codegen/src/symboltable.rs
  • crates/common/src/format.rs
  • crates/common/src/str.rs
  • crates/derive-impl/src/pyclass.rs
  • crates/derive-impl/src/pystructseq.rs
  • crates/stdlib/src/_asyncio.rs
  • crates/stdlib/src/contextvars.rs
  • crates/stdlib/src/csv.rs
  • crates/stdlib/src/mmap.rs
  • crates/stdlib/src/posixsubprocess.rs
  • crates/stdlib/src/socket.rs
  • crates/stdlib/src/ssl.rs
  • crates/stdlib/src/ssl/cert.rs
  • crates/stdlib/src/ssl/compat.rs
  • crates/stdlib/src/unicodedata.rs
  • crates/vm/src/buffer.rs
  • crates/vm/src/builtins/builtin_func.rs
  • crates/vm/src/builtins/code.rs
  • crates/vm/src/builtins/function.rs
  • crates/vm/src/builtins/interpolation.rs
  • crates/vm/src/builtins/range.rs
  • crates/vm/src/builtins/set.rs
  • crates/vm/src/builtins/type.rs
  • crates/vm/src/codecs.rs
  • crates/vm/src/exception_group.rs
  • crates/vm/src/exceptions.rs
  • crates/vm/src/format.rs
  • crates/vm/src/frame.rs
  • crates/vm/src/getpath.rs
  • crates/vm/src/import.rs
  • crates/vm/src/ospath.rs
  • crates/vm/src/stdlib/_abc.rs
  • crates/vm/src/stdlib/_ast/python.rs
  • crates/vm/src/stdlib/_ctypes.rs
  • crates/vm/src/stdlib/_ctypes/array.rs
  • crates/vm/src/stdlib/_ctypes/base.rs
  • crates/vm/src/stdlib/_ctypes/function.rs
  • crates/vm/src/stdlib/_ctypes/pointer.rs
  • crates/vm/src/stdlib/_ctypes/simple.rs
  • crates/vm/src/stdlib/_ctypes/structure.rs
  • crates/vm/src/stdlib/_ctypes/union.rs
  • crates/vm/src/stdlib/_io.rs
  • crates/vm/src/stdlib/_sre.rs
  • crates/vm/src/stdlib/_sysconfigdata.rs
  • crates/vm/src/stdlib/_thread.rs
  • crates/vm/src/stdlib/builtins.rs
  • crates/vm/src/stdlib/itertools.rs
  • crates/vm/src/stdlib/sys.rs
  • crates/vm/src/stdlib/time.rs
  • crates/vm/src/types/structseq.rs
  • crates/vm/src/vm/mod.rs
  • crates/vm/src/warn.rs

Comment thread crates/stdlib/src/csv.rs
Comment on lines +1028 to +1030
if let Ok(t) = String::from_utf8(trim_spaces(&buffer[range]).to_vec())
.unwrap()
.parse::<i64>()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix panic risk from .unwrap() and avoid redundant UTF-8 conversion.

Line 1029 contains an .unwrap() call that can panic if UTF-8 conversion fails, violating Rust error handling best practices. Additionally, the code converts the buffer slice to UTF-8 twice: once on line 1022 (producing s) and again on lines 1028-1029. Since s is already a validated UTF-8 string, you can trim and parse it directly.

🔧 Proposed fix
                     let s = core::str::from_utf8(&buffer[range.clone()])
                         // not sure if this is possible - the input was all strings
                         .map_err(|_e| vm.new_unicode_decode_error("csv not utf8"))?;
                     // Rustpython TODO!
                     // Incomplete implementation
                     if let QuoteStyle::Nonnumeric = zelf.dialect.quoting {
-                        if let Ok(t) = String::from_utf8(trim_spaces(&buffer[range]).to_vec())
-                            .unwrap()
-                            .parse::<i64>()
-                        {
+                        if let Ok(t) = s.trim().parse::<i64>() {
                             Ok(vm.ctx.new_int(t).into())
                         } else {
                             Ok(vm.ctx.new_str(s).into())

Based on learnings: Follow Rust best practices for error handling and memory management.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/stdlib/src/csv.rs` around lines 1028 - 1030, Replace the redundant and
panicking UTF-8 conversion by using the already-validated string `s`: instead of
calling String::from_utf8(...).unwrap().parse::<i64>(), trim and parse the slice
of `s` (e.g., `s[range].trim().parse::<i64>()`) and match on the parse Result
(e.g., `if let Ok(t) = ...`) so you never call `.unwrap()`; ensure you drop the
extra conversion of `buffer` and only operate on `s`, keeping error handling via
the parse result.

Comment thread crates/vm/src/format.rs
Comment on lines +2111 to 2119
Some("l" | "q") => {
if let Ok(i) = obj.try_int(vm) {
*(result as *mut i64) = i.as_bigint().to_i64().unwrap_or(0);
}
}
Some("L") | Some("Q") => {
Some("L" | "Q") => {
if let Ok(i) = obj.try_int(vm) {
*(result as *mut u64) = i.as_bigint().to_u64().unwrap_or(0);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== get_ffi_type width mapping for l/L =="
rg -n -C3 '"l" =>|\"L\" =>' crates/vm/src/stdlib/_ctypes.rs

echo
echo "== python_to_ffi write targets for l/L/q/Q =="
rg -n -C4 'Some\("l" \| "q"\)|Some\("L" \| "Q"\)|Some\("l"\)|Some\("L"\)|Some\("q"\)|Some\("Q"\)' crates/vm/src/stdlib/_ctypes/function.rs

Repository: RustPython/RustPython

Length of output: 213


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Code at lines 2111-2119 in function.rs ==="
sed -n '2108,2122p' crates/vm/src/stdlib/_ctypes/function.rs

echo
echo "=== Search for get_ffi_type l/L mappings ==="
rg -n '"l"|"L"' crates/vm/src/stdlib/_ctypes.rs | head -20

Repository: RustPython/RustPython

Length of output: 809


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== get_ffi_type mappings for l and L (lines 165-185) ==="
sed -n '165,185p' crates/vm/src/stdlib/_ctypes.rs

echo
echo "=== Check libc crate for c_long/c_ulong definitions ==="
rg -n 'c_long|c_ulong' crates/vm/src/stdlib/_ctypes.rs | head -10

Repository: RustPython/RustPython

Length of output: 1357


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check for other pointer cast patterns in python_to_ffi ==="
sed -n '2050,2150p' crates/vm/src/stdlib/_ctypes/function.rs | grep -n -E 'Some\(|as \*mut|=>|^\s*}'

Repository: RustPython/RustPython

Length of output: 2404


Fix platform-width regression for 'l'/'L' callback writes.

Lines 2111 and 2116 incorrectly write i64/u64 for both ("l" | "q") and ("L" | "Q"). The get_ffi_type function maps "l" to c_long (4 bytes on 32-bit platforms, 8 on 64-bit) and "L" to c_ulong. Grouping them with "q"/"Q" (always 8 bytes) causes buffer overruns: writing 8 bytes into a 4-byte result slot corrupts memory on 32-bit targets.

Separate the cases and write to the correct platform-dependent types:

Suggested fix
-            Some("l" | "q") => {
+            Some("l") => {
+                if let Ok(i) = obj.try_int(vm) {
+                    *(result as *mut libc::c_long) =
+                        i.as_bigint().to_i64().unwrap_or(0) as libc::c_long;
+                }
+            }
+            Some("q") => {
                 if let Ok(i) = obj.try_int(vm) {
                     *(result as *mut i64) = i.as_bigint().to_i64().unwrap_or(0);
                 }
             }
-            Some("L" | "Q") => {
+            Some("L") => {
+                if let Ok(i) = obj.try_int(vm) {
+                    *(result as *mut libc::c_ulong) =
+                        i.as_bigint().to_u64().unwrap_or(0) as libc::c_ulong;
+                }
+            }
+            Some("Q") => {
                 if let Ok(i) = obj.try_int(vm) {
                     *(result as *mut u64) = i.as_bigint().to_u64().unwrap_or(0);
                 }
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm/src/stdlib/_ctypes/function.rs` around lines 2111 - 2119, The
current match arm incorrectly groups "l"/"L" with "q"/"Q" and always writes
8-byte i64/u64 values, causing buffer overruns on 32-bit targets; update the
match in the callback writer so "l" and "L" are handled separately from "q"/"Q":
for "l" write into the result as the platform-dependent c_long type (use the
module's c_long type and convert the BigInt to an i64 then cast to c_long with a
safe fallback), for "L" write as c_ulong (convert via to_u64 then cast to
c_ulong with fallback), and keep "q"/"Q" writing i64/u64 as before; reference
the existing match arms for ("l" | "q"), ("L" | "Q"), get_ffi_type, and the
result pointer handling so you change the pointer casts to *mut c_long/*mut
c_ulong for "l"/"L" respectively instead of *mut i64/*mut u64.

@youknowone youknowone merged commit 926d69b into RustPython:main May 2, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants