From eab3a31c5750013c53c0eb02adc976d6757dc9f7 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Thu, 2 Jul 2026 01:32:03 +0900 Subject: chore(lint): ban std::io::Read/Write, Any, Command use imports Extends no_banned_use to cover std::any::Any, std::io::Read/Write, and std::process::Command, and teaches the linter to allow `as _` imports so trait methods can still be brought into scope without binding the banned name. Fully qualifies all existing usages across the codebase. --- crates/shirabe-php-rpc/src/lib.rs | 2 +- crates/shirabe-php-shim/src/fs.rs | 6 +----- crates/shirabe-php-shim/src/process.rs | 2 +- crates/shirabe-php-shim/src/stream.rs | 3 +-- crates/shirabe-php-shim/src/xml.rs | 11 +++++------ crates/shirabe/src/package/archiver/archiver_interface.rs | 4 +--- crates/shirabe/src/repository/filesystem_repository.rs | 3 +-- crates/shirabe/src/util/http/curl_downloader.rs | 2 +- crates/shirabe/tests/all_functional_test.rs | 3 +-- crates/shirabe/tests/repository/vcs_repository_test.rs | 5 ++--- scripts/linters/no_banned_use.rb | 14 ++++++++++++-- 11 files changed, 27 insertions(+), 28 deletions(-) diff --git a/crates/shirabe-php-rpc/src/lib.rs b/crates/shirabe-php-rpc/src/lib.rs index 2bddc77..d55381b 100644 --- a/crates/shirabe-php-rpc/src/lib.rs +++ b/crates/shirabe-php-rpc/src/lib.rs @@ -1,7 +1,7 @@ //! Rust-to-PHP RPC over a Unix domain socket. See `docs/dev/php-rpc.md`. use shirabe_external_packages::symfony::process::PhpExecutableFinder; -use std::io::{Read, Write}; +use std::io::{Read as _, Write as _}; use std::os::unix::net::{UnixListener, UnixStream}; use std::sync::{LazyLock, Mutex}; use std::time::{Duration, Instant}; diff --git a/crates/shirabe-php-shim/src/fs.rs b/crates/shirabe-php-shim/src/fs.rs index ba6eef6..e58623a 100644 --- a/crates/shirabe-php-shim/src/fs.rs +++ b/crates/shirabe-php-shim/src/fs.rs @@ -4,6 +4,7 @@ use crate::StreamBacking; use crate::StreamState; use crate::UnexpectedValueException; use indexmap::IndexMap; +use std::io::{Read as _, Write as _}; pub const PHP_EOL: &str = "\n"; @@ -329,7 +330,6 @@ pub fn fopen(file: &str, mode: &str) -> Result { /// PHP `fwrite()`. `length` caps the number of bytes written (`None` = whole string). /// Returns the byte count written, or `None` for PHP's `false`-on-failure. pub fn fwrite(stream: &PhpResource, data: &str, length: Option) -> Option { - use std::io::Write; let bytes = data.as_bytes(); let bytes = match length { Some(l) if l >= 0 => &bytes[..(l as usize).min(bytes.len())], @@ -360,7 +360,6 @@ pub fn fwrite(stream: &PhpResource, data: &str, length: Option) -> Option; from_utf8_lossy can corrupt /// binary reads (filesAreEqual / binary copy). pub fn fread(stream: &PhpResource, length: i64) -> Option { - use std::io::Read; let cap = length.max(0) as usize; match stream { PhpResource::Stdin => { @@ -482,7 +481,6 @@ fn fgets_read_line( /// PHP `fgetc()`: reads a single byte, or `None` at end-of-stream. /// TODO(phase-e): byte-string semantics — should return Vec. pub fn fgetc(stream: &PhpResource) -> Option { - use std::io::Read; let mut byte = [0u8; 1]; match stream { PhpResource::Stdin => { @@ -638,7 +636,6 @@ fn build_stat_map(size: u64, file_meta: Option<&std::fs::Metadata>) -> IndexMap< /// PHP `fflush()`. pub fn fflush(stream: &PhpResource) -> bool { - use std::io::Write; match stream { PhpResource::Stdin => true, PhpResource::Stdout => std::io::stdout().flush().is_ok(), @@ -848,7 +845,6 @@ pub fn file_put_contents(_path: &str, _data: &[u8]) -> Option { } pub fn file_put_contents3(_filename: &str, _data: &str, _flags: i64) -> Option { - use std::io::Write; // TODO(phase-d): the LOCK_EX and FILE_USE_INCLUDE_PATH flags are ignored; only FILE_APPEND is // honored. let append = _flags & FILE_APPEND != 0; diff --git a/crates/shirabe-php-shim/src/process.rs b/crates/shirabe-php-shim/src/process.rs index ad6e1d5..901d345 100644 --- a/crates/shirabe-php-shim/src/process.rs +++ b/crates/shirabe-php-shim/src/process.rs @@ -52,7 +52,7 @@ pub fn shell_exec(command: &str) -> Option { } pub fn system(command: &str, result_code: Option<&mut i64>) -> Option { - use std::io::Write; + use std::io::Write as _; let result = std::process::Command::new("/bin/sh") .arg("-c") .arg(command) diff --git a/crates/shirabe-php-shim/src/stream.rs b/crates/shirabe-php-shim/src/stream.rs index 98f0322..ce6048c 100644 --- a/crates/shirabe-php-shim/src/stream.rs +++ b/crates/shirabe-php-shim/src/stream.rs @@ -1,5 +1,6 @@ use crate::{PhpMixed, PhpResource, StreamBacking}; use indexmap::IndexMap; +use std::io::{Read as _, Write as _}; pub const STREAM_NOTIFY_FAILURE: i64 = 9; pub const STREAM_NOTIFY_FILE_SIZE_IS: i64 = 5; @@ -30,7 +31,6 @@ pub fn stream_get_contents_with_max( // Reads from the stream's current position: all remaining bytes, or up to `max_length` when given // (a negative max means "until end"). fn stream_read_remaining(stream: &PhpResource, max_length: Option) -> Option { - use std::io::Read; match stream { PhpResource::Stdin => { let mut buf = Vec::new(); @@ -139,7 +139,6 @@ pub fn stream_get_wrappers() -> Vec { /// PHP `stream_copy_to_stream()`: copy the remaining bytes of `source` into `dest`, returning the /// number of bytes copied (or `None` for `false`-on-failure). pub fn stream_copy_to_stream(source: &PhpResource, dest: &PhpResource) -> Option { - use std::io::{Read, Write}; let mut buf = Vec::new(); match source { PhpResource::Stdin => { diff --git a/crates/shirabe-php-shim/src/xml.rs b/crates/shirabe-php-shim/src/xml.rs index cc323ca..b3938da 100644 --- a/crates/shirabe-php-shim/src/xml.rs +++ b/crates/shirabe-php-shim/src/xml.rs @@ -5,7 +5,6 @@ //! handles over that graph. use std::cell::RefCell; -use std::io::Write; use std::rc::{Rc, Weak}; #[derive(Debug, Clone, Copy, PartialEq)] @@ -120,7 +119,7 @@ impl DOMDocument { self.0.borrow_mut().format_output = value; } - pub fn save_xml(&self, writer: &mut W) -> std::io::Result<()> { + pub fn save_xml(&self, writer: &mut W) -> std::io::Result<()> { let doc = self.0.borrow(); writeln!( writer, @@ -250,7 +249,7 @@ fn collect_by_tag( } } -fn serialize_node( +fn serialize_node( node: &Rc>, depth: usize, format: bool, @@ -305,14 +304,14 @@ fn serialize_node( Ok(()) } -fn write_indent(out: &mut W, depth: usize) -> std::io::Result<()> { +fn write_indent(out: &mut W, depth: usize) -> std::io::Result<()> { for _ in 0..depth { out.write_all(b" ")?; } Ok(()) } -fn escape_text(s: &str, out: &mut W) -> std::io::Result<()> { +fn escape_text(s: &str, out: &mut W) -> std::io::Result<()> { let mut buf = [0u8; 4]; for c in s.chars() { match c { @@ -326,7 +325,7 @@ fn escape_text(s: &str, out: &mut W) -> std::io::Result<()> { Ok(()) } -fn escape_attribute(s: &str, out: &mut W) -> std::io::Result<()> { +fn escape_attribute(s: &str, out: &mut W) -> std::io::Result<()> { let mut buf = [0u8; 4]; for c in s.chars() { match c { diff --git a/crates/shirabe/src/package/archiver/archiver_interface.rs b/crates/shirabe/src/package/archiver/archiver_interface.rs index 54121b5..d50c96a 100644 --- a/crates/shirabe/src/package/archiver/archiver_interface.rs +++ b/crates/shirabe/src/package/archiver/archiver_interface.rs @@ -1,7 +1,5 @@ //! ref: composer/src/Composer/Package/Archiver/ArchiverInterface.php -use std::any::Any; - pub trait ArchiverInterface { fn archive( &self, @@ -15,5 +13,5 @@ pub trait ArchiverInterface { fn supports(&self, format: String, source_type: Option) -> bool; /// PHP `$archiver instanceof X` checks; allow downcasting from `dyn ArchiverInterface`. - fn as_any(&self) -> &dyn Any; + fn as_any(&self) -> &dyn std::any::Any; } diff --git a/crates/shirabe/src/repository/filesystem_repository.rs b/crates/shirabe/src/repository/filesystem_repository.rs index 0e17841..7d59bb0 100644 --- a/crates/shirabe/src/repository/filesystem_repository.rs +++ b/crates/shirabe/src/repository/filesystem_repository.rs @@ -26,7 +26,6 @@ use shirabe_php_shim::{ is_array, is_null, is_string, ksort, realpath, str_repeat, trim, usort, var_export, }; use shirabe_semver::constraint::AnyConstraint; -use std::any::Any; /// Filesystem repository. #[derive(Debug)] @@ -825,7 +824,7 @@ impl RepositoryInterface for FilesystemRepository { self.inner.get_repo_name() } - fn as_any(&self) -> &dyn Any { + fn as_any(&self) -> &dyn std::any::Any { self } diff --git a/crates/shirabe/src/util/http/curl_downloader.rs b/crates/shirabe/src/util/http/curl_downloader.rs index 0d8248b..6a6a1d6 100644 --- a/crates/shirabe/src/util/http/curl_downloader.rs +++ b/crates/shirabe/src/util/http/curl_downloader.rs @@ -632,7 +632,7 @@ impl CurlDownloader { max_file_size: Option, filename: Option<&str>, ) -> Result { - use std::io::{Read, Write}; + use std::io::{Read as _, Write as _}; let mut stream = resp; let mut written: u64 = 0; diff --git a/crates/shirabe/tests/all_functional_test.rs b/crates/shirabe/tests/all_functional_test.rs index 594f064..57788a3 100644 --- a/crates/shirabe/tests/all_functional_test.rs +++ b/crates/shirabe/tests/all_functional_test.rs @@ -12,7 +12,6 @@ use shirabe_external_packages::composer::pcre::preg::Preg; use shirabe_php_shim::{CaptureKey, PREG_SPLIT_DELIM_CAPTURE, PhpMixed, intval}; use std::cell::RefCell; use std::path::{Path, PathBuf}; -use std::process::Command; /// ref: AllFunctionalTest's `$oldcwd` / `$testDir` instance state plus its `setUp`/`tearDown`. /// @@ -213,7 +212,7 @@ fn run_integration(test_filename: &str) { let run = &test_data["RUN"]; let command_line = format!("'{}' --no-ansi {} 2>&1", bin, run); - let proc = Command::new("sh") + let proc = std::process::Command::new("sh") .arg("-c") .arg(&command_line) .current_dir(&test_dir) diff --git a/crates/shirabe/tests/repository/vcs_repository_test.rs b/crates/shirabe/tests/repository/vcs_repository_test.rs index ed705e8..1ee72cb 100644 --- a/crates/shirabe/tests/repository/vcs_repository_test.rs +++ b/crates/shirabe/tests/repository/vcs_repository_test.rs @@ -12,7 +12,6 @@ use shirabe::util::http_downloader::HttpDownloader; use shirabe::util::r#loop::Loop; use shirabe_php_shim::PhpMixed; use std::cell::RefCell; -use std::process::Command; use std::rc::Rc; use tempfile::TempDir; @@ -31,7 +30,7 @@ fn set_up() -> Option { let path = git_repo.path(); let exec = |args: &[&str]| { - let status = Command::new("git") + let status = std::process::Command::new("git") .args(args) .current_dir(path) .env("GIT_CONFIG_GLOBAL", "/dev/null") @@ -129,7 +128,7 @@ fn composer(version: Option<&str>) -> PhpMixed { } fn which_git() -> Option<()> { - Command::new("git") + std::process::Command::new("git") .arg("--version") .output() .ok() diff --git a/scripts/linters/no_banned_use.rb b/scripts/linters/no_banned_use.rb index 341a2b9..311d03c 100644 --- a/scripts/linters/no_banned_use.rb +++ b/scripts/linters/no_banned_use.rb @@ -1,5 +1,9 @@ BANNED_USE_PATHS = %w[ anyhow::Result + std::any::Any + std::io::Read + std::io::Write + std::process::Command ].freeze def no_banned_use(root_dir, excludes = []) @@ -14,7 +18,8 @@ def no_banned_use(root_dir, excludes = []) return true if errors.empty? puts 'Found banned `use` imports.' - puts 'These items must always be referenced by their fully-qualified path:' + puts 'These items must always be referenced by their fully-qualified path.' + puts 'For imports to use trait methods, use `as _` (e.g., `use std::io::Write as _;`).' errors.each do |err| puts " #{err}" end @@ -63,7 +68,10 @@ def expand_use_tree(tree) brace = tree.index('{') if brace.nil? - return [strip_use_alias(tree)].reject(&:empty?) + stripped = strip_use_alias(tree) + return [] if stripped.nil? + + return [stripped].reject(&:empty?) end prefix = tree[0...brace].sub(/::\s*\z/, '').strip @@ -83,6 +91,8 @@ def expand_use_tree(tree) end def strip_use_alias(segment) + return nil if segment =~ /\s+as\s+_\s*\z/ + segment.sub(/\s+as\s+\S+\s*\z/, '').strip end -- cgit v1.3.1