aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-18 01:57:02 +0900
committernsfisis <nsfisis@gmail.com>2026-08-18 01:57:02 +0900
commit050c56ef263d90d862ef565bc1762909110e02eb (patch)
treecb0887f9dc9a75910c72244d884463cc13778ca1
parent7061051e19dc0ccbbdb694f030aedb05802287e4 (diff)
downloadphp-shirabe-050c56ef263d90d862ef565bc1762909110e02eb.tar.gz
php-shirabe-050c56ef263d90d862ef565bc1762909110e02eb.tar.zst
php-shirabe-050c56ef263d90d862ef565bc1762909110e02eb.zip
fix(class-map-generator): anchor the type keyword search
PhpFileCleaner::clean scans for the single class/interface/trait keyword of a one-declaration file with a pattern PHP runs anchored (`A`) one char before the keyword. The port dropped the anchor and relied on the leftmost match of an offset search instead, on the grounds that the keyword sits exactly one char past the offset. That holds for the keyword but not for the guards around it: where the preceding char makes PCRE fail (`Foo::class`, `$class`, `->class`), the unanchored search does not fail, it matches the next declaration further down the file and returns the cleaned prefix cut short there. Given <?php namespace A { $x = Foo::class; } namespace B { class Bar {} } PhpFileParser::findClasses reported A\Bar where PHP reports B\Bar, because the `namespace B {` the cleaner skipped past never reached the parser. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
-rw-r--r--crates/shirabe-class-map-generator/src/php_file_cleaner.rs11
1 files changed, 5 insertions, 6 deletions
diff --git a/crates/shirabe-class-map-generator/src/php_file_cleaner.rs b/crates/shirabe-class-map-generator/src/php_file_cleaner.rs
index cfd8f77f..80aa9ce6 100644
--- a/crates/shirabe-class-map-generator/src/php_file_cleaner.rs
+++ b/crates/shirabe-class-map-generator/src/php_file_cleaner.rs
@@ -1,7 +1,7 @@
//! ref: composer/vendor/composer/class-map-generator/src/PhpFileCleaner.php
use indexmap::IndexMap;
-use shirabe_php_shim::{PregMatches, preg_match, preg_match2};
+use shirabe_php_shim::{PregMatches, preg_match};
use std::sync::Mutex;
#[derive(Debug, Clone)]
@@ -40,11 +40,10 @@ impl PhpFileCleaner {
// consumed char plus both guards collapse into one negated class
// `[^a-zA-Z0-9_$:>]` (the `\w` set reproducing `\b`, plus the three operators).
// The possessive quantifiers (`++`, `*+`) are performance-only and become plain
- // `+`/`*`. The leftmost-match semantics of `captures_at(.., offset)` stand in for
- // the dropped `A` (anchored) modifier, since the keyword is known to sit exactly
- // one char past the search offset.
+ // `+`/`*`. The `A` (anchored) modifier becomes a leading `^` over the sub-slice
+ // that begins at the search offset.
pattern: format!(
- "{{[^a-zA-Z0-9_$:>]{}\\s+[a-zA-Z_\\x7f-\\xff:][a-zA-Z0-9_\\x7f-\\xff:\\-]*}}is",
+ "{{^[^a-zA-Z0-9_$:>]{}\\s+[a-zA-Z_\\x7f-\\xff:][a-zA-Z0-9_\\x7f-\\xff:\\-]*}}is",
r#type
),
},
@@ -147,7 +146,7 @@ impl PhpFileCleaner {
if end <= self.len && self.contents[self.index..end] == entry.name {
let offset = if self.index > 0 { self.index - 1 } else { 0 };
if let Some(r#match) =
- preg_match2(&entry.pattern, &self.contents, offset)
+ preg_match(&entry.pattern, &self.contents[offset..])
{
return clean + r#match.get(0).unwrap_or("");
}