diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-18 01:57:02 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-18 01:57:02 +0900 |
| commit | 050c56ef263d90d862ef565bc1762909110e02eb (patch) | |
| tree | cb0887f9dc9a75910c72244d884463cc13778ca1 /crates/shirabe-class-map-generator/src/php_file_cleaner.rs | |
| parent | 7061051e19dc0ccbbdb694f030aedb05802287e4 (diff) | |
| download | php-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>
Diffstat (limited to 'crates/shirabe-class-map-generator/src/php_file_cleaner.rs')
| -rw-r--r-- | crates/shirabe-class-map-generator/src/php_file_cleaner.rs | 11 |
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(""); } |
