aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-07-02 01:32:03 +0900
committernsfisis <nsfisis@gmail.com>2026-07-02 01:34:49 +0900
commiteab3a31c5750013c53c0eb02adc976d6757dc9f7 (patch)
treec84b4bc6243668eb79c00af98e00800c2951077b
parentdda045eb663524b40e277047e3cea301738e5c26 (diff)
downloadphp-shirabe-eab3a31c5750013c53c0eb02adc976d6757dc9f7.tar.gz
php-shirabe-eab3a31c5750013c53c0eb02adc976d6757dc9f7.tar.zst
php-shirabe-eab3a31c5750013c53c0eb02adc976d6757dc9f7.zip
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.
-rw-r--r--crates/shirabe-php-rpc/src/lib.rs2
-rw-r--r--crates/shirabe-php-shim/src/fs.rs6
-rw-r--r--crates/shirabe-php-shim/src/process.rs2
-rw-r--r--crates/shirabe-php-shim/src/stream.rs3
-rw-r--r--crates/shirabe-php-shim/src/xml.rs11
-rw-r--r--crates/shirabe/src/package/archiver/archiver_interface.rs4
-rw-r--r--crates/shirabe/src/repository/filesystem_repository.rs3
-rw-r--r--crates/shirabe/src/util/http/curl_downloader.rs2
-rw-r--r--crates/shirabe/tests/all_functional_test.rs3
-rw-r--r--crates/shirabe/tests/repository/vcs_repository_test.rs5
-rw-r--r--scripts/linters/no_banned_use.rb14
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<PhpResource, std::io::Error> {
/// 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<i64>) -> Option<i64> {
- 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<i64>) -> Option<i
/// TODO(phase-e): byte-string semantics — should return Vec<u8>; from_utf8_lossy can corrupt
/// binary reads (filesAreEqual / binary copy).
pub fn fread(stream: &PhpResource, length: i64) -> Option<String> {
- use std::io::Read;
let cap = length.max(0) as usize;
match stream {
PhpResource::Stdin => {
@@ -482,7 +481,6 @@ fn fgets_read_line<R: std::io::Read + ?Sized>(
/// PHP `fgetc()`: reads a single byte, or `None` at end-of-stream.
/// TODO(phase-e): byte-string semantics — should return Vec<u8>.
pub fn fgetc(stream: &PhpResource) -> Option<String> {
- 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<i64> {
}
pub fn file_put_contents3(_filename: &str, _data: &str, _flags: i64) -> Option<i64> {
- 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<String> {
}
pub fn system(command: &str, result_code: Option<&mut i64>) -> Option<String> {
- 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<i64>) -> Option<String> {
- use std::io::Read;
match stream {
PhpResource::Stdin => {
let mut buf = Vec::new();
@@ -139,7 +139,6 @@ pub fn stream_get_wrappers() -> Vec<String> {
/// 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<i64> {
- 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<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
+ pub fn save_xml<W: std::io::Write>(&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<W: Write>(
+fn serialize_node<W: std::io::Write>(
node: &Rc<RefCell<NodeInner>>,
depth: usize,
format: bool,
@@ -305,14 +304,14 @@ fn serialize_node<W: Write>(
Ok(())
}
-fn write_indent<W: Write>(out: &mut W, depth: usize) -> std::io::Result<()> {
+fn write_indent<W: std::io::Write>(out: &mut W, depth: usize) -> std::io::Result<()> {
for _ in 0..depth {
out.write_all(b" ")?;
}
Ok(())
}
-fn escape_text<W: Write>(s: &str, out: &mut W) -> std::io::Result<()> {
+fn escape_text<W: std::io::Write>(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<W: Write>(s: &str, out: &mut W) -> std::io::Result<()> {
Ok(())
}
-fn escape_attribute<W: Write>(s: &str, out: &mut W) -> std::io::Result<()> {
+fn escape_attribute<W: std::io::Write>(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<String>) -> 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<u64>,
filename: Option<&str>,
) -> Result<Body, (String, bool)> {
- 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<SetUp> {
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