diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-07-21 02:54:18 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-07-23 22:07:16 +0900 |
| commit | 765b7749d31675d3cbf541b146ead1aafd6d6ae9 (patch) | |
| tree | 11f8a07cd9e3d4ef92bb2f75a0811e41b1d928ba /scripts/plugin-class-classifier/src/MethodInfo.php | |
| parent | 770013c7097b6b5c0c49c7fa46d9235c308c4ad5 (diff) | |
| download | php-shirabe-765b7749d31675d3cbf541b146ead1aafd6d6ae9.tar.gz php-shirabe-765b7749d31675d3cbf541b146ead1aafd6d6ae9.tar.zst php-shirabe-765b7749d31675d3cbf541b146ead1aafd6d6ae9.zip | |
feat(plugin-class-classifier): add deterministic plugin-boundary classifier
Decides, for every composer/composer class, how it is treated at the
plugin boundary (rust-proxy / rust-snapshot / contract / two-world /
php-native / unsupported) so that upstream updates re-classify new or
rewritten classes without re-deriving the design by hand. Rules and
category definitions live in docs/dev/plugin-class-classification.md;
the tool (PHP + nikic/PHP-Parser) implements them as a reachability
closure with direction marks, per-method pure/mutator analysis, and a
leaf-first fixed point for unreachable classes, with three small
versioned exception lists.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'scripts/plugin-class-classifier/src/MethodInfo.php')
| -rw-r--r-- | scripts/plugin-class-classifier/src/MethodInfo.php | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/scripts/plugin-class-classifier/src/MethodInfo.php b/scripts/plugin-class-classifier/src/MethodInfo.php new file mode 100644 index 00000000..a03c2126 --- /dev/null +++ b/scripts/plugin-class-classifier/src/MethodInfo.php @@ -0,0 +1,71 @@ +<?php + +declare(strict_types=1); + +namespace Shirabe\PluginClassifier; + +final class MethodInfo +{ + /** Filled by BodyAnalyzer. */ + public bool $mutatesThisDirectly = false; + + /** + * Calls to methods of the same object ($this->m(), self::m(), + * static::m(), parent::m()) with a literal name. Purity propagates + * through these; thisArgs lists 0-based argument positions holding + * $this-rooted expressions (checked against by-ref parameters). + * + * @var list<array{name: string, thisArgs: list<int>}> + */ + public array $selfCalls = []; + + /** + * Calls on receivers whose class could be resolved statically (typed + * property or typed parameter) that pass $this-rooted expressions. + * Checked against the callee's by-ref parameter positions once the whole + * symbol table is available. + * + * @var list<array{class: string, method: string, thisArgs: list<int>}> + */ + public array $externalCalls = []; + + /** + * True when the body contains a call whose signature cannot be resolved + * statically (dynamic method name, variable function, call_user_func, + * closure) with a $this-rooted expression (or $this itself) as argument, + * or passes a $this-rooted expression into a by-ref parameter position. + */ + public bool $thisEscapesUnresolved = false; + + public function __construct( + public readonly string $name, + /** 'public' | 'protected' | 'private' */ + public readonly string $visibility, + public readonly bool $static, + public readonly bool $abstract, + /** @var list<ParamInfo> */ + public readonly array $params, + /** Class-like FQCNs in the native return type. @var list<string> */ + public readonly array $returnClassTypes, + /** Native return type is array/iterable/mixed/object or absent. */ + public readonly bool $returnExpandable, + /** Class-like FQCNs from the `@return` docblock. @var list<string> */ + public readonly array $docblockReturnTypes, + /** Class-like FQCNs from `@throws` docblocks. @var list<string> */ + public readonly array $docblockThrowsTypes, + ) { + } + + /** @return list<int> positions of by-ref parameters */ + public function byRefParamPositions(): array + { + $positions = []; + foreach ($this->params as $i => $param) { + if ($param->byRef) { + $positions[] = $i; + } + } + + return $positions; + } +} |
