aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-class-map-generator/src/class_map_generator.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-08 22:14:12 +0900
committernsfisis <nsfisis@gmail.com>2026-08-08 22:14:12 +0900
commitf4cad2123b2af0de72bda4ce039e16e74f163f4e (patch)
tree21803308c5ff41e23c9d3b117433eea16b4ff663 /crates/shirabe-class-map-generator/src/class_map_generator.rs
parent0209f63210e5b547b5c6b73367bb80ea86c255ec (diff)
downloadphp-shirabe-f4cad2123b2af0de72bda4ce039e16e74f163f4e.tar.gz
php-shirabe-f4cad2123b2af0de72bda4ce039e16e74f163f4e.tar.zst
php-shirabe-f4cad2123b2af0de72bda4ce039e16e74f163f4e.zip
feat(php-shim): give ported exceptions PHP's class hierarchy
Ported exceptions were flat structs reached with `downcast_ref`, so Composer's `catch (\RuntimeException $e)` only matched the exact leaf type and `get_class($e)` had nothing to report. Each exception now embeds an instance of the class it extends and travels inside an `AnyThrowable`; `Catch::catch`/`catch_mut` walk that chain, and `PhpClass::php_class_name` yields the PHP FQCN. Dropping the `std::error::Error` impls from the exception types leaves `AnyThrowable` as the only route into an `anyhow::Error`, so the walk cannot be bypassed. A `no_exception_downcast` linter catches the `downcast::<X>()` calls that would now silently answer `None`. Three sites change behavior as a result: the `TransportException` exit-code override reaches `MaxFileSizeExceededException`, the `catch (\LogicException)` in findSimilar() reaches its subclasses, and rendered exception titles carry the real class name rather than a guess. `get_class_err()` is no longer a `todo!()`, which re-enables FilesystemRepositoryTest::testCorruptedRepositoryFile. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-class-map-generator/src/class_map_generator.rs')
-rw-r--r--crates/shirabe-class-map-generator/src/class_map_generator.rs71
1 files changed, 32 insertions, 39 deletions
diff --git a/crates/shirabe-class-map-generator/src/class_map_generator.rs b/crates/shirabe-class-map-generator/src/class_map_generator.rs
index 0f98ca27..d1a11c99 100644
--- a/crates/shirabe-class-map-generator/src/class_map_generator.rs
+++ b/crates/shirabe-class-map-generator/src/class_map_generator.rs
@@ -74,19 +74,15 @@ impl ClassMapGenerator {
excluded_dirs: Vec<String>,
) -> anyhow::Result<()> {
if !matches!(autoload_type, "psr-0" | "psr-4" | "classmap") {
- return Err(anyhow::anyhow!(InvalidArgumentException {
- message: "$autoloadType must be one of: \"psr-0\", \"psr-4\" or \"classmap\""
- .to_string(),
- code: 0,
- }));
+ return Err(InvalidArgumentException::new(
+ "$autoloadType must be one of: \"psr-0\", \"psr-4\" or \"classmap\"".to_string(),
+ )
+ .into());
}
let base_path: Option<String> = if autoload_type != "classmap" {
if namespace.is_none() {
- return Err(anyhow::anyhow!(InvalidArgumentException {
- message: "$namespace must be given (even if it is an empty string if you do not want to filter) when specifying a psr-0 or psr-4 autoload type".to_string(),
- code: 0,
- }));
+ return Err(InvalidArgumentException::new("$namespace must be given (even if it is an empty string if you do not want to filter) when specifying a psr-0 or psr-4 autoload type".to_string()).into());
}
Some(path.to_owned())
} else {
@@ -116,13 +112,10 @@ impl ClassMapGenerator {
.iter()
.collect()
} else {
- return Err(anyhow::anyhow!(RuntimeException {
- message: format!(
- "Could not scan for classes inside \"{}\" which does not appear to be a file nor a folder",
- path
- ),
- code: 0,
- }));
+ return Err(RuntimeException::new(format!(
+ "Could not scan for classes inside \"{}\" which does not appear to be a file nor a folder",
+ path
+ )).into());
};
let cwd = realpath(getcwd().unwrap_or_default()).unwrap_or_default();
@@ -131,10 +124,11 @@ impl ClassMapGenerator {
let mut file_path = match file.to_str() {
Some(s) => s.to_string(),
None => {
- return Err(anyhow::anyhow!(RuntimeException {
- message: format!("Path contains invalid UTF-8: {}", file.display()),
- code: 0,
- }));
+ return Err(RuntimeException::new(format!(
+ "Path contains invalid UTF-8: {}",
+ file.display()
+ ))
+ .into());
}
};
let ext = pathinfo(&file_path, PATHINFO_EXTENSION);
@@ -158,10 +152,11 @@ impl ClassMapGenerator {
}
if file_path.is_empty() {
- return Err(anyhow::anyhow!(LogicException {
- message: format!("Got an empty $filePath for {}", file.display()),
- code: 0,
- }));
+ return Err(LogicException::new(format!(
+ "Got an empty $filePath for {}",
+ file.display()
+ ))
+ .into());
}
let real_path = if is_stream_wrapper_path {
@@ -170,13 +165,11 @@ impl ClassMapGenerator {
match realpath(&file_path) {
Some(p) => p,
None => {
- return Err(anyhow::anyhow!(RuntimeException {
- message: format!(
- "realpath of {} failed to resolve, got false",
- file_path
- ),
- code: 0,
- }));
+ return Err(RuntimeException::new(format!(
+ "realpath of {} failed to resolve, got false",
+ file_path
+ ))
+ .into());
}
}
};
@@ -284,10 +277,10 @@ impl ClassMapGenerator {
};
sub_path = str_replace("\\", DIRECTORY_SEPARATOR, &sub_namespace);
} else {
- return Err(anyhow::anyhow!(InvalidArgumentException {
- message: "$namespaceType must be \"psr-0\" or \"psr-4\"".to_string(),
- code: 0,
- }));
+ return Err(InvalidArgumentException::new(
+ "$namespaceType must be \"psr-0\" or \"psr-4\"".to_string(),
+ )
+ .into());
}
if sub_path == real_sub_path {
@@ -403,10 +396,10 @@ impl ClassMapGenerator {
fn get_cwd() -> anyhow::Result<String> {
match getcwd() {
Some(cwd) => Ok(cwd),
- None => Err(anyhow::anyhow!(RuntimeException {
- message: "Could not determine the current working directory".to_string(),
- code: 0,
- })),
+ None => Err(RuntimeException::new(
+ "Could not determine the current working directory".to_string(),
+ )
+ .into()),
}
}
}