Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b93ad8b
Parse @pure-unless-callable-is-impure PHPDoc tag
zonuexe Jul 2, 2026
b103f39
Thread pure-unless-callable-is-impure through the reflection layer
zonuexe Jul 2, 2026
83ab4a7
Wire pure-unless-callable-is-impure into the analyser
zonuexe Jul 2, 2026
14dbc2c
Mark callback-accepting builtins as pure-unless-callable-is-impure
zonuexe Jul 2, 2026
cc3c0a8
Add tests for @pure-unless-callable-is-impure
zonuexe Jul 2, 2026
e1fb83c
Fix pure-unless-callable-is-impure parameter flag propagation
zonuexe Jul 2, 2026
84ddffa
Suppress call impure points when pure-unless-callable-is-impure callb…
zonuexe Jul 2, 2026
49eed1f
Fix CI: avoid named arguments, adjust no-effect fixture
zonuexe Jul 2, 2026
8cd2e63
Cover pure-unless-callable-is-impure verdict for maybe-null and maybe…
zonuexe Jul 3, 2026
4cfd61a
Simplify pure-unless-callable-is-impure metadata reads
zonuexe Jul 3, 2026
5a31338
Document the shape of the function metadata array
zonuexe Jul 3, 2026
e3e4b6a
Mark array_all() and array_any() as pure-unless-callable-is-impure
zonuexe Jul 3, 2026
625d506
Honor pure-unless-callable-is-impure metadata for stub-reflected func…
zonuexe Jul 3, 2026
e7c4b29
Add lint version comment to the PHP 8.4 pure-unless fixture
zonuexe Jul 3, 2026
e23483b
Honor @pure-unless-callable-is-impure on methods
zonuexe Jul 5, 2026
c45ca89
Note the two paths that intentionally don't thread pure-unless yet
zonuexe Jul 5, 2026
09b962b
Honor @pure-unless-callable-is-impure on constructor calls
zonuexe Jul 5, 2026
ce5e53a
Drop the native mixed property type from the pure-unless fixture
zonuexe Jul 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 38 additions & 10 deletions bin/functionMetadata_original.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
<?php declare(strict_types = 1);

/**
* Hand-maintained side-effect metadata for built-in functions and methods,
* keyed by lowercase function name or "Class::method". resources/functionMetadata.php
* is generated from this file by bin/generate-function-metadata.php.
*
* Each entry is exactly one of these shapes:
*
* - ['hasSideEffects' => bool]
* false: the call is pure. true: the call has side effects.
* - ['pureUnlessCallableIsImpureParameters' => array<string, true>]
* the call is pure unless one of the listed callable parameters
* (keyed by parameter name) receives an impure callable, e.g. array_map()
* whose only side effects come from its 'callback' argument.
*/

/** @var array<string, array{hasSideEffects: bool}|array{pureUnlessCallableIsImpureParameters: array<string, bool>}> */
return [
'abs' => ['hasSideEffects' => false],
'acos' => ['hasSideEffects' => false],
Expand All @@ -20,6 +36,8 @@
'apcu_key_info' => ['hasSideEffects' => true],
'apcu_sma_info' => ['hasSideEffects' => true],
'apcu_store' => ['hasSideEffects' => true],
'array_all' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_any' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_change_key_case' => ['hasSideEffects' => false],
'array_chunk' => ['hasSideEffects' => false],
'array_column' => ['hasSideEffects' => false],
Expand All @@ -28,39 +46,44 @@
'array_diff' => ['hasSideEffects' => false],
'array_diff_assoc' => ['hasSideEffects' => false],
'array_diff_key' => ['hasSideEffects' => false],
'array_diff_uassoc' => ['hasSideEffects' => false],
'array_diff_ukey' => ['hasSideEffects' => false],
'array_diff_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['key_compare_func' => true]],
'array_diff_ukey' => ['pureUnlessCallableIsImpureParameters' => ['key_comp_func' => true]],
'array_fill' => ['hasSideEffects' => false],
'array_fill_keys' => ['hasSideEffects' => false],
'array_filter' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_find' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_find_key' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_flip' => ['hasSideEffects' => false],
'array_intersect' => ['hasSideEffects' => false],
'array_intersect_assoc' => ['hasSideEffects' => false],
'array_intersect_key' => ['hasSideEffects' => false],
'array_intersect_uassoc' => ['hasSideEffects' => false],
'array_intersect_ukey' => ['hasSideEffects' => false],
'array_intersect_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['key_compare_func' => true]],
'array_intersect_ukey' => ['pureUnlessCallableIsImpureParameters' => ['key_compare_func' => true]],
'array_key_first' => ['hasSideEffects' => false],
'array_key_last' => ['hasSideEffects' => false],
'array_key_exists' => ['hasSideEffects' => false],
'array_keys' => ['hasSideEffects' => false],
'array_map' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_merge' => ['hasSideEffects' => false],
'array_merge_recursive' => ['hasSideEffects' => false],
'array_pad' => ['hasSideEffects' => false],
'array_pop' => ['hasSideEffects' => true],
'array_product' => ['hasSideEffects' => false],
'array_push' => ['hasSideEffects' => true],
'array_rand' => ['hasSideEffects' => false],
'array_reduce' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_replace' => ['hasSideEffects' => false],
'array_replace_recursive' => ['hasSideEffects' => false],
'array_reverse' => ['hasSideEffects' => false],
'array_shift' => ['hasSideEffects' => true],
'array_slice' => ['hasSideEffects' => false],
'array_sum' => ['hasSideEffects' => false],
'array_udiff' => ['hasSideEffects' => false],
'array_udiff_assoc' => ['hasSideEffects' => false],
'array_udiff_uassoc' => ['hasSideEffects' => false],
'array_uintersect' => ['hasSideEffects' => false],
'array_uintersect_assoc' => ['hasSideEffects' => false],
'array_uintersect_uassoc' => ['hasSideEffects' => false],
'array_udiff' => ['pureUnlessCallableIsImpureParameters' => ['data_comp_func' => true]],
'array_udiff_assoc' => ['pureUnlessCallableIsImpureParameters' => ['key_comp_func' => true]],
'array_udiff_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['data_comp_func' => true, 'key_comp_func' => true]],
'array_uintersect' => ['pureUnlessCallableIsImpureParameters' => ['data_compare_func' => true]],
'array_uintersect_assoc' => ['pureUnlessCallableIsImpureParameters' => ['data_compare_func' => true]],
'array_uintersect_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['data_compare_func' => true, 'key_compare_func' => true]],
'array_unique' => ['hasSideEffects' => false],
'array_unshift' => ['hasSideEffects' => true],
'array_values' => ['hasSideEffects' => false],
Expand All @@ -81,6 +104,8 @@
'bcround' => ['hasSideEffects' => false],
'bcfloor' => ['hasSideEffects' => false],
'bcceil' => ['hasSideEffects' => false],
'call_user_func' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'call_user_func_array' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
// continue functionMap.php, line 424
'chgrp' => ['hasSideEffects' => true],
'chmod' => ['hasSideEffects' => true],
Expand All @@ -97,6 +122,8 @@
'file_put_contents' => ['hasSideEffects' => true],
'flock' => ['hasSideEffects' => true],
'fopen' => ['hasSideEffects' => true],
'forward_static_call' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'forward_static_call_array' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'fpassthru' => ['hasSideEffects' => true],
'fputcsv' => ['hasSideEffects' => true],
'fputs' => ['hasSideEffects' => true],
Expand Down Expand Up @@ -237,6 +264,7 @@
'output_reset_rewrite_vars' => ['hasSideEffects' => true],
'pclose' => ['hasSideEffects' => true],
'popen' => ['hasSideEffects' => true],
'preg_replace_callback' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'readfile' => ['hasSideEffects' => true],
'rename' => ['hasSideEffects' => true],
'rewind' => ['hasSideEffects' => true],
Expand Down
44 changes: 40 additions & 4 deletions bin/generate-function-metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,21 @@ public function enterNode(Node $node)
);
}

/** @var array<string, array{hasSideEffects: bool}> $metadata */
/** @var array<string, array{hasSideEffects?: bool, pureUnlessCallableIsImpureParameters?: array<string, bool>}> $metadata */
$metadata = require __DIR__ . '/functionMetadata_original.php';
foreach ($visitor->functions as $functionName) {
if (array_key_exists($functionName, $metadata)) {
if ($metadata[$functionName]['hasSideEffects']) {
if (isset($metadata[$functionName]['hasSideEffects']) && $metadata[$functionName]['hasSideEffects']) {
throw new ShouldNotHappenException($functionName);
}

if (isset($metadata[$functionName]['pureUnlessCallableIsImpureParameters'])) {
$metadata[$functionName] = [
'pureUnlessCallableIsImpureParameters' => $metadata[$functionName]['pureUnlessCallableIsImpureParameters'],
];

continue;
}
}
$metadata[$functionName] = ['hasSideEffects' => false];
}
Expand Down Expand Up @@ -177,19 +185,47 @@ public function enterNode(Node $node)
* 2) Contribute the functions that have 'hasSideEffects' => true as a modification to bin/functionMetadata_original.php.
* 3) Contribute the #[Pure] functions without side effects to https://github.com/JetBrains/phpstorm-stubs
* 4) Once the PR from 3) is merged, please update the package here and run ./bin/generate-function-metadata.php.
*
* The array is keyed by lowercase function name or "Class::method". Each entry is
* exactly one of:
* - ['hasSideEffects' => bool] - false: pure, true: has side effects.
* - ['pureUnlessCallableIsImpureParameters' => array<string, true>] - pure unless
* one of the listed callable parameters (keyed by parameter name) receives an
* impure callable, e.g. array_map()'s 'callback'.
*/

/** @var array<string, array{hasSideEffects: bool}|array{pureUnlessCallableIsImpureParameters: array<string, bool>}> */
return [
%s
];
php;
$content = '';
$escape = static fn (mixed $value): string => var_export($value, true);
$encodeHasSideEffects = static fn (array $meta) => [$escape('hasSideEffects'), $escape($meta['hasSideEffects'])];
$encodePureUnlessCallableIsImpureParameters = static fn (array $meta) => [
$escape('pureUnlessCallableIsImpureParameters'),
sprintf(
'[%s]',
implode(
' ,',
array_map(
static fn ($key, $param) => sprintf('%s => %s', $escape($key), $escape($param)),
array_keys($meta['pureUnlessCallableIsImpureParameters']),
$meta['pureUnlessCallableIsImpureParameters'],
),
),
),
];

foreach ($metadata as $name => $meta) {
$content .= sprintf(
"\t%s => [%s => %s],\n",
var_export($name, true),
var_export('hasSideEffects', true),
var_export($meta['hasSideEffects'], true),
...match (true) {
isset($meta['hasSideEffects']) => $encodeHasSideEffects($meta),
isset($meta['pureUnlessCallableIsImpureParameters']) => $encodePureUnlessCallableIsImpureParameters($meta),
default => throw new ShouldNotHappenException($escape($meta)),
},
);
}

Expand Down
42 changes: 31 additions & 11 deletions resources/functionMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@
* 2) Contribute the functions that have 'hasSideEffects' => true as a modification to bin/functionMetadata_original.php.
* 3) Contribute the #[Pure] functions without side effects to https://github.com/JetBrains/phpstorm-stubs
* 4) Once the PR from 3) is merged, please update the package here and run ./bin/generate-function-metadata.php.
*
* The array is keyed by lowercase function name or "Class::method". Each entry is
* exactly one of:
* - ['hasSideEffects' => bool] - false: pure, true: has side effects.
* - ['pureUnlessCallableIsImpureParameters' => array<string, true>] - pure unless
* one of the listed callable parameters (keyed by parameter name) receives an
* impure callable, e.g. array_map()'s 'callback'.
*/

/** @var array<string, array{hasSideEffects: bool}|array{pureUnlessCallableIsImpureParameters: array<string, bool>}> */
return [
'BackedEnum::from' => ['hasSideEffects' => false],
'BackedEnum::tryFrom' => ['hasSideEffects' => false],
Expand Down Expand Up @@ -725,6 +733,8 @@
'apcu_key_info' => ['hasSideEffects' => true],
'apcu_sma_info' => ['hasSideEffects' => true],
'apcu_store' => ['hasSideEffects' => true],
'array_all' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_any' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_change_key_case' => ['hasSideEffects' => false],
'array_chunk' => ['hasSideEffects' => false],
'array_column' => ['hasSideEffects' => false],
Expand All @@ -733,43 +743,48 @@
'array_diff' => ['hasSideEffects' => false],
'array_diff_assoc' => ['hasSideEffects' => false],
'array_diff_key' => ['hasSideEffects' => false],
'array_diff_uassoc' => ['hasSideEffects' => false],
'array_diff_ukey' => ['hasSideEffects' => false],
'array_diff_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['key_compare_func' => true]],
Comment thread
staabm marked this conversation as resolved.
'array_diff_ukey' => ['pureUnlessCallableIsImpureParameters' => ['key_comp_func' => true]],
'array_fill' => ['hasSideEffects' => false],
'array_fill_keys' => ['hasSideEffects' => false],
'array_filter' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_find' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_find_key' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_first' => ['hasSideEffects' => false],
'array_flip' => ['hasSideEffects' => false],
'array_intersect' => ['hasSideEffects' => false],
'array_intersect_assoc' => ['hasSideEffects' => false],
'array_intersect_key' => ['hasSideEffects' => false],
'array_intersect_uassoc' => ['hasSideEffects' => false],
'array_intersect_ukey' => ['hasSideEffects' => false],
'array_intersect_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['key_compare_func' => true]],
'array_intersect_ukey' => ['pureUnlessCallableIsImpureParameters' => ['key_compare_func' => true]],
'array_is_list' => ['hasSideEffects' => false],
'array_key_exists' => ['hasSideEffects' => false],
'array_key_first' => ['hasSideEffects' => false],
'array_key_last' => ['hasSideEffects' => false],
'array_keys' => ['hasSideEffects' => false],
'array_last' => ['hasSideEffects' => false],
'array_map' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_merge' => ['hasSideEffects' => false],
'array_merge_recursive' => ['hasSideEffects' => false],
'array_pad' => ['hasSideEffects' => false],
'array_pop' => ['hasSideEffects' => true],
'array_product' => ['hasSideEffects' => false],
'array_push' => ['hasSideEffects' => true],
'array_rand' => ['hasSideEffects' => false],
'array_reduce' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'array_replace' => ['hasSideEffects' => false],
'array_replace_recursive' => ['hasSideEffects' => false],
'array_reverse' => ['hasSideEffects' => false],
'array_search' => ['hasSideEffects' => false],
'array_shift' => ['hasSideEffects' => true],
'array_slice' => ['hasSideEffects' => false],
'array_sum' => ['hasSideEffects' => false],
'array_udiff' => ['hasSideEffects' => false],
'array_udiff_assoc' => ['hasSideEffects' => false],
'array_udiff_uassoc' => ['hasSideEffects' => false],
'array_uintersect' => ['hasSideEffects' => false],
'array_uintersect_assoc' => ['hasSideEffects' => false],
'array_uintersect_uassoc' => ['hasSideEffects' => false],
'array_udiff' => ['pureUnlessCallableIsImpureParameters' => ['data_comp_func' => true]],
'array_udiff_assoc' => ['pureUnlessCallableIsImpureParameters' => ['key_comp_func' => true]],
'array_udiff_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['data_comp_func' => true ,'key_comp_func' => true]],
'array_uintersect' => ['pureUnlessCallableIsImpureParameters' => ['data_compare_func' => true]],
'array_uintersect_assoc' => ['pureUnlessCallableIsImpureParameters' => ['data_compare_func' => true]],
'array_uintersect_uassoc' => ['pureUnlessCallableIsImpureParameters' => ['data_compare_func' => true ,'key_compare_func' => true]],
'array_unique' => ['hasSideEffects' => false],
'array_unshift' => ['hasSideEffects' => true],
'array_values' => ['hasSideEffects' => false],
Expand Down Expand Up @@ -803,6 +818,8 @@
'bzerror' => ['hasSideEffects' => false],
'bzerrstr' => ['hasSideEffects' => false],
'bzopen' => ['hasSideEffects' => false],
'call_user_func' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'call_user_func_array' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'ceil' => ['hasSideEffects' => false],
'checkdate' => ['hasSideEffects' => false],
'checkdnsrr' => ['hasSideEffects' => false],
Expand Down Expand Up @@ -954,6 +971,8 @@
'fmod' => ['hasSideEffects' => false],
'fnmatch' => ['hasSideEffects' => true],
'fopen' => ['hasSideEffects' => true],
'forward_static_call' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'forward_static_call_array' => ['pureUnlessCallableIsImpureParameters' => ['function' => true]],
'fpassthru' => ['hasSideEffects' => true],
'fputcsv' => ['hasSideEffects' => true],
'fputs' => ['hasSideEffects' => true],
Expand Down Expand Up @@ -1616,6 +1635,7 @@
'preg_last_error' => ['hasSideEffects' => true],
'preg_last_error_msg' => ['hasSideEffects' => true],
'preg_quote' => ['hasSideEffects' => false],
'preg_replace_callback' => ['pureUnlessCallableIsImpureParameters' => ['callback' => true]],
'preg_split' => ['hasSideEffects' => false],
'property_exists' => ['hasSideEffects' => false],
'quoted_printable_decode' => ['hasSideEffects' => false],
Expand Down Expand Up @@ -1757,4 +1777,4 @@
'zlib_encode' => ['hasSideEffects' => false],
'zlib_get_coding_type' => ['hasSideEffects' => false],

];
];
21 changes: 14 additions & 7 deletions src/Analyser/ExprHandler/NewHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use PHPStan\DependencyInjection\Type\DynamicThrowTypeExtensionProvider;
use PHPStan\Node\MethodReturnStatementsNode;
use PHPStan\Parser\NewAssignedToPropertyVisitor;
use PHPStan\Reflection\Callables\SimpleImpurePoint;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Dummy\DummyConstructorReflection;
use PHPStan\Reflection\ExtendedParametersAcceptor;
Expand Down Expand Up @@ -258,13 +259,19 @@
if ($constructorReflection !== null) {
if (!$constructorReflection->hasSideEffects()->no()) {
$certain = $constructorReflection->isPure()->no();
$impurePoints[] = new ImpurePoint(
$scope,
$expr,
'new',
sprintf('instantiation of class %s', $constructorReflection->getDeclaringClass()->getDisplayName()),
$certain,
);
$verdict = SimpleImpurePoint::resolvePureUnlessCallableIsImpureVerdict($parametersAcceptor, $scope, $expr->getArgs());
if ($verdict === null || !$verdict->yes()) {

Check warning on line 263 in src/Analyser/ExprHandler/NewHandler.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ if (!$constructorReflection->hasSideEffects()->no()) { $certain = $constructorReflection->isPure()->no(); $verdict = SimpleImpurePoint::resolvePureUnlessCallableIsImpureVerdict($parametersAcceptor, $scope, $expr->getArgs()); - if ($verdict === null || !$verdict->yes()) { + if ($verdict === null || $verdict->no()) { if ($verdict !== null && $verdict->no()) { $certain = true; }

Check warning on line 263 in src/Analyser/ExprHandler/NewHandler.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ if (!$constructorReflection->hasSideEffects()->no()) { $certain = $constructorReflection->isPure()->no(); $verdict = SimpleImpurePoint::resolvePureUnlessCallableIsImpureVerdict($parametersAcceptor, $scope, $expr->getArgs()); - if ($verdict === null || !$verdict->yes()) { + if ($verdict === null || $verdict->no()) { if ($verdict !== null && $verdict->no()) { $certain = true; }
if ($verdict !== null && $verdict->no()) {

Check warning on line 264 in src/Analyser/ExprHandler/NewHandler.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.3, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ $certain = $constructorReflection->isPure()->no(); $verdict = SimpleImpurePoint::resolvePureUnlessCallableIsImpureVerdict($parametersAcceptor, $scope, $expr->getArgs()); if ($verdict === null || !$verdict->yes()) { - if ($verdict !== null && $verdict->no()) { + if ($verdict !== null && !$verdict->yes()) { $certain = true; } $impurePoints[] = new ImpurePoint(

Check warning on line 264 in src/Analyser/ExprHandler/NewHandler.php

View workflow job for this annotation

GitHub Actions / Mutation Testing (8.4, ubuntu-latest)

Escaped Mutant for Mutator "PHPStan\Infection\TrinaryLogicMutator": @@ @@ $certain = $constructorReflection->isPure()->no(); $verdict = SimpleImpurePoint::resolvePureUnlessCallableIsImpureVerdict($parametersAcceptor, $scope, $expr->getArgs()); if ($verdict === null || !$verdict->yes()) { - if ($verdict !== null && $verdict->no()) { + if ($verdict !== null && !$verdict->yes()) { $certain = true; } $impurePoints[] = new ImpurePoint(
$certain = true;
}
$impurePoints[] = new ImpurePoint(
$scope,
$expr,
'new',
sprintf('instantiation of class %s', $constructorReflection->getDeclaringClass()->getDisplayName()),
$certain,
);
}
}
} elseif ($classReflection === null) {
$impurePoints[] = new ImpurePoint(
Expand Down
7 changes: 7 additions & 0 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -1534,6 +1534,7 @@ public function enterTrait(ClassReflection $traitReflection): self
* @param Type[] $parameterOutTypes
* @param array<string, bool> $immediatelyInvokedCallableParameters
* @param array<string, Type> $phpDocClosureThisTypeParameters
* @param array<string, bool> $phpDocPureUnlessCallableIsImpureParameters
*/
public function enterClassMethod(
Node\Stmt\ClassMethod $classMethod,
Expand All @@ -1555,6 +1556,7 @@ public function enterClassMethod(
array $phpDocClosureThisTypeParameters = [],
bool $isConstructor = false,
?ResolvedPhpDocBlock $resolvedPhpDocBlock = null,
array $phpDocPureUnlessCallableIsImpureParameters = [],
): self
{
if (!$this->isInClass()) {
Expand Down Expand Up @@ -1590,6 +1592,7 @@ public function enterClassMethod(
array_map(fn (Type $type): Type => $this->transformStaticType(TemplateTypeHelper::toArgument($type)), $phpDocClosureThisTypeParameters),
$isConstructor,
$this->attributeReflectionFactory->fromAttrGroups($classMethod->attrGroups, InitializerExprContext::fromStubParameter($this->getClassReflection()->getName(), $this->getFile(), $classMethod)),
$phpDocPureUnlessCallableIsImpureParameters,
),
!$classMethod->isStatic(),
);
Expand Down Expand Up @@ -1679,6 +1682,7 @@ public function enterPropertyHook(
[],
false,
$this->attributeReflectionFactory->fromAttrGroups($hook->attrGroups, InitializerExprContext::fromStubParameter($this->getClassReflection()->getName(), $this->getFile(), $hook)),
[],
),
true,
);
Expand Down Expand Up @@ -1755,6 +1759,7 @@ private function getParameterAttributes(ClassMethod|Function_|PropertyHook $func
* @param Type[] $parameterOutTypes
* @param array<string, bool> $immediatelyInvokedCallableParameters
* @param array<string, Type> $phpDocClosureThisTypeParameters
* @param array<string, bool> $pureUnlessCallableIsImpureParameters
*/
public function enterFunction(
Node\Stmt\Function_ $function,
Expand All @@ -1772,6 +1777,7 @@ public function enterFunction(
array $parameterOutTypes = [],
array $immediatelyInvokedCallableParameters = [],
array $phpDocClosureThisTypeParameters = [],
array $pureUnlessCallableIsImpureParameters = [],
): self
{
return $this->enterFunctionLike(
Expand All @@ -1797,6 +1803,7 @@ public function enterFunction(
$immediatelyInvokedCallableParameters,
$phpDocClosureThisTypeParameters,
$this->attributeReflectionFactory->fromAttrGroups($function->attrGroups, InitializerExprContext::fromStubParameter(null, $this->getFile(), $function)),
$pureUnlessCallableIsImpureParameters,
),
false,
);
Expand Down
Loading
Loading