diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 93a16ba06e..d51bce4983 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -716,13 +716,14 @@ private function processStmtNode( $hasYield = false; $throwPoints = []; $impurePoints = []; - $this->processAttributeGroups($stmt, $stmt->attrGroups, $scope, $storage, $nodeCallback); [$templateTypeMap, $phpDocParameterTypes, $phpDocImmediatelyInvokedCallableParameters, $phpDocClosureThisTypeParameters, $phpDocReturnType, $phpDocThrowType, $deprecatedDescription, $isDeprecated, $isInternal, $isFinal, $isPure, $acceptsNamedArguments, $isReadOnly, $phpDocComment, $asserts, $selfOutType, $phpDocParameterOutTypes] = $this->getPhpDocs($scope, $stmt); foreach ($stmt->params as $param) { $this->processParamNode($stmt, $param, $scope, $storage, $nodeCallback); } + $this->processAttributeGroups($stmt, $stmt->attrGroups, $scope, $storage, $nodeCallback); + if ($stmt->returnType !== null) { $this->callNodeCallback($nodeCallback, $stmt->returnType, $scope, $storage); } diff --git a/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php b/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php index 778dbf90f7..def62d6a98 100644 --- a/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php +++ b/tests/PHPStan/Analyser/ParameterClosureTypeExtensionArrowFunctionTest.php @@ -11,6 +11,9 @@ class ParameterClosureTypeExtensionArrowFunctionTest extends TypeInferenceTestCa public static function dataFileAsserts(): iterable { yield from self::gatherAssertTypes(__DIR__ . '/data/parameter-closure-type-extension-arrow-function.php'); + if (PHP_VERSION_ID >= 80500) { + yield from self::gatherAssertTypes(__DIR__ . '/data/closure-type-in-constant-expression-php85.php'); + } } /** diff --git a/tests/PHPStan/Analyser/data/closure-type-in-constant-expression-php85.php b/tests/PHPStan/Analyser/data/closure-type-in-constant-expression-php85.php new file mode 100644 index 0000000000..17d9aff9d3 --- /dev/null +++ b/tests/PHPStan/Analyser/data/closure-type-in-constant-expression-php85.php @@ -0,0 +1,83 @@ +getName() !== '__construct') { + return false; + } + + if ($methodReflection->getDeclaringClass()->getName() !== Idempotency::class) { + return false; + } + + return $parameter->getName() === 'key'; + } + + public function getTypeFromStaticMethodCall( + MethodReflection $methodReflection, + StaticCall $methodCall, + ParameterReflection $parameter, + Scope $scope + ): ?Type { + // Just some garbage, that doesn't throw an error anyway. + return new CallableType( + [ + new NativeParameterReflection('test', false, new FloatType(), PassedByReference::createNo(), false, null), + ], + new MixedType() + ); + + // What we need here, is a way to find out that this is being called from `__invoke` + // using $scope->getFunctionName() + // Then we would want to find out the 1st parameter of __invoke + // It would be SomeCommand. + // Then we would want to return that the callable signature is `static function (SomeCommand): string` + // But I'm not sure if this is the correct extension point at all... + // It seems it's not. + } +} + +class SomeCommand {} + +#[Attribute(flags: Attribute::TARGET_METHOD)] +final readonly class Idempotency +{ + /** + * @param Closure(object): string $key + */ + public function __construct( + public Closure $key, + ) { + } +} + +class SomeHandler +{ + #[Idempotency(key: static function (object $command) : string { + assertType(SomeCommand::class, $command); + + return 'hello'; + })] + public function __invoke(SomeCommand $command): void + { + } +} + diff --git a/tests/PHPStan/Analyser/parameter-closure-type-extension-arrow-function.neon b/tests/PHPStan/Analyser/parameter-closure-type-extension-arrow-function.neon index 2ab556183c..50a3edd10b 100644 --- a/tests/PHPStan/Analyser/parameter-closure-type-extension-arrow-function.neon +++ b/tests/PHPStan/Analyser/parameter-closure-type-extension-arrow-function.neon @@ -14,3 +14,8 @@ services: tags: - phpstan.staticMethodParameterClosureTypeExtension + - + class: \ClosureTypeInConstantExpressionPhp85\StaticMethodParameterClosureTypeExtension + tags: + - phpstan.staticMethodParameterClosureTypeExtension +