From 2c921012a606e36f2d03cc12d3a2eb406c96851f Mon Sep 17 00:00:00 2001 From: ondrejmirtes <104888+ondrejmirtes@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:28:38 +0000 Subject: [PATCH 1/2] Allow passing return values of by-reference functions/methods as by-ref args - Functions and methods that return by reference (declared with &) produce valid lvalues that can be passed to by-reference parameters - Added callReturnsByReference() helper to FunctionCallParametersCheck that resolves reflection for MethodCall, StaticCall, and FuncCall nodes and checks returnsByReference() - Injected ReflectionProvider into FunctionCallParametersCheck for resolving function reflections - New regression test in tests/PHPStan/Rules/Functions/data/bug-757.php --- CLAUDE.md | 4 ++ src/Rules/FunctionCallParametersCheck.php | 48 +++++++++++++++++++ .../Analyser/Bug9307CallMethodsRuleTest.php | 2 +- .../Rules/Classes/ClassAttributesRuleTest.php | 1 + .../ClassConstantAttributesRuleTest.php | 1 + .../ForbiddenNameCheckExtensionRuleTest.php | 2 +- .../Rules/Classes/InstantiationRuleTest.php | 2 +- .../Constants/ConstantAttributesRuleTest.php | 1 + .../EnumCases/EnumCaseAttributesRuleTest.php | 1 + .../ArrowFunctionAttributesRuleTest.php | 1 + .../Rules/Functions/CallCallablesRuleTest.php | 4 +- .../CallToFunctionParametersRuleTest.php | 16 ++++++- .../Rules/Functions/CallUserFuncRuleTest.php | 2 +- .../Functions/ClosureAttributesRuleTest.php | 1 + .../Functions/FunctionAttributesRuleTest.php | 1 + .../Functions/ParamAttributesRuleTest.php | 1 + .../PHPStan/Rules/Functions/data/bug-757.php | 41 ++++++++++++++++ .../Rules/Methods/CallMethodsRuleTest.php | 2 +- .../Methods/CallStaticMethodsRuleTest.php | 1 + .../Methods/MethodAttributesRuleTest.php | 1 + .../Properties/PropertyAttributesRuleTest.php | 1 + .../PropertyHookAttributesRuleTest.php | 1 + .../Rules/Traits/TraitAttributesRuleTest.php | 1 + 23 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 tests/PHPStan/Rules/Functions/data/bug-757.php diff --git a/CLAUDE.md b/CLAUDE.md index c2df251460..c47bba7bce 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -306,6 +306,10 @@ PHPStan tracks whether expressions/statements have side effects ("impure points" Bugs occur when impure points are missed (e.g. inherited constructors of anonymous classes) or when `clearstatcache()` calls don't invalidate filesystem function return types. +### FunctionCallParametersCheck: by-reference argument validation + +`FunctionCallParametersCheck` (`src/Rules/FunctionCallParametersCheck.php`) validates arguments passed to functions/methods. For by-reference parameters, it checks whether the argument is a valid lvalue (variable, array dim fetch, property fetch). It also allows function/method calls that return by reference (`&getString()`, `&staticGetString()`, `&refFunction()`), using `returnsByReference()` on the resolved reflection. The class is manually instantiated in ~20 test files, so adding a constructor parameter requires updating all of them. The `Scope` interface provides `getMethodReflection()` for method calls, while `ReflectionProvider` (injected into the class) is needed for resolving function reflections. + ### Testing patterns - **Rule tests**: Extend `RuleTestCase`, implement `getRule()`, call `$this->analyse([__DIR__ . '/data/my-test.php'], [...expected errors...])`. Expected errors are `[message, line]` pairs. Test data files live in `tests/PHPStan/Rules/*/data/`. diff --git a/src/Rules/FunctionCallParametersCheck.php b/src/Rules/FunctionCallParametersCheck.php index a41177bc1e..61c80b7199 100644 --- a/src/Rules/FunctionCallParametersCheck.php +++ b/src/Rules/FunctionCallParametersCheck.php @@ -11,6 +11,7 @@ use PHPStan\Reflection\ExtendedParameterReflection; use PHPStan\Reflection\ParameterReflection; use PHPStan\Reflection\ParametersAcceptor; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Reflection\ResolvedFunctionVariant; use PHPStan\Rules\PhpDoc\UnresolvableTypeHelper; use PHPStan\Rules\Properties\PropertyReflectionFinder; @@ -47,6 +48,7 @@ public function __construct( private NullsafeCheck $nullsafeCheck, private UnresolvableTypeHelper $unresolvableTypeHelper, private PropertyReflectionFinder $propertyReflectionFinder, + private ReflectionProvider $reflectionProvider, #[AutowiredParameter(ref: '%checkFunctionArgumentTypes%')] private bool $checkArgumentTypes, #[AutowiredParameter] @@ -462,6 +464,10 @@ public function check( continue; } + if ($this->callReturnsByReference($argumentValue, $scope)) { + continue; + } + $errors[] = RuleErrorBuilder::message(sprintf( $parameterPassedByReferenceMessage, $this->describeParameter($parameter, $argumentName === null ? $i + 1 : null), @@ -690,4 +696,46 @@ private function describeParameter(ParameterReflection $parameter, int|string|nu return implode(' ', $parts); } + private function callReturnsByReference(Expr $expr, Scope $scope): bool + { + if ($expr instanceof Node\Expr\MethodCall) { + if (!$expr->name instanceof Node\Identifier) { + return false; + } + $calledOnType = $scope->getType($expr->var); + $methodReflection = $scope->getMethodReflection($calledOnType, $expr->name->name); + if ($methodReflection === null) { + return false; + } + return $methodReflection->returnsByReference()->yes(); + } + + if ($expr instanceof Node\Expr\StaticCall) { + if (!$expr->name instanceof Node\Identifier) { + return false; + } + if ($expr->class instanceof Node\Name) { + $calledOnType = $scope->resolveTypeByName($expr->class); + } else { + $calledOnType = $scope->getType($expr->class); + } + $methodReflection = $scope->getMethodReflection($calledOnType, $expr->name->name); + if ($methodReflection === null) { + return false; + } + return $methodReflection->returnsByReference()->yes(); + } + + if ($expr instanceof Node\Expr\FuncCall) { + if ($expr->name instanceof Node\Name) { + if ($this->reflectionProvider->hasFunction($expr->name, $scope)) { + $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); + return $functionReflection->returnsByReference()->yes(); + } + } + } + + return false; + } + } diff --git a/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php b/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php index a7342e7506..73bb6e8729 100644 --- a/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php +++ b/tests/PHPStan/Analyser/Bug9307CallMethodsRuleTest.php @@ -24,7 +24,7 @@ protected function getRule(): Rule $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false, true); return new CallMethodsRule( new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), - new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true), ); } diff --git a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php index 978eb83e71..722c5a194a 100644 --- a/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassAttributesRuleTest.php @@ -37,6 +37,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php b/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php index 8e594f53eb..c3b4dbac19 100644 --- a/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ClassConstantAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php b/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php index 64eedaa7cb..fe5b61f3c0 100644 --- a/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php +++ b/tests/PHPStan/Rules/Classes/ForbiddenNameCheckExtensionRuleTest.php @@ -27,7 +27,7 @@ protected function getRule(): Rule return new InstantiationRule( $container, $reflectionProvider, - new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), + new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck($container), diff --git a/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php b/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php index 26a872d9e8..89557169d0 100644 --- a/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php +++ b/tests/PHPStan/Rules/Classes/InstantiationRuleTest.php @@ -27,7 +27,7 @@ protected function getRule(): Rule return new InstantiationRule( $container, $reflectionProvider, - new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), + new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, false, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true), new ClassNameCheck( new ClassCaseSensitivityCheck($reflectionProvider, true), new ClassForbiddenNameCheck($container), diff --git a/tests/PHPStan/Rules/Constants/ConstantAttributesRuleTest.php b/tests/PHPStan/Rules/Constants/ConstantAttributesRuleTest.php index 698d60678c..d6753f61c9 100644 --- a/tests/PHPStan/Rules/Constants/ConstantAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Constants/ConstantAttributesRuleTest.php @@ -38,6 +38,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php b/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php index 1b43de86af..12219b4da5 100644 --- a/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php +++ b/tests/PHPStan/Rules/EnumCases/EnumCaseAttributesRuleTest.php @@ -33,6 +33,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php index 7f26ab879e..4efd904b72 100644 --- a/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ArrowFunctionAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php index bd8ad74e49..a065aa99e7 100644 --- a/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallCallablesRuleTest.php @@ -23,13 +23,15 @@ class CallCallablesRuleTest extends RuleTestCase protected function getRule(): Rule { - $ruleLevelHelper = new RuleLevelHelper(self::createReflectionProvider(), true, false, true, $this->checkExplicitMixed, false, false, true); + $reflectionProvider = self::createReflectionProvider(); + $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, true, false, true, $this->checkExplicitMixed, false, false, true); return new CallCallablesRule( new FunctionCallParametersCheck( $ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 86ceccf6d9..9121d4b2c7 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -30,7 +30,7 @@ protected function getRule(): Rule $broker = self::createReflectionProvider(); return new CallToFunctionParametersRule( $broker, - new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), + new FunctionCallParametersCheck(new RuleLevelHelper($broker, true, false, true, $this->checkExplicitMixed, $this->checkImplicitMixed, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $broker, true, true, true, true), ); } @@ -308,6 +308,20 @@ public function testPassingNonVariableToParameterPassedByReference(): void ]); } + public function testBug757(): void + { + $this->analyse([__DIR__ . '/data/bug-757.php'], [ + [ + 'Parameter #1 $s of function Bug757\useString is passed by reference, so it expects variables only.', + 37, + ], + [ + 'Parameter #1 $s of function Bug757\useString is passed by reference, so it expects variables only.', + 40, + ], + ]); + } + public function testImplodeOnPhp74(): void { $errors = [ diff --git a/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php b/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php index ba44a5bc0f..dd4b3259a8 100644 --- a/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallUserFuncRuleTest.php @@ -20,7 +20,7 @@ class CallUserFuncRuleTest extends RuleTestCase protected function getRule(): Rule { $reflectionProvider = self::createReflectionProvider(); - return new CallUserFuncRule($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true)); + return new CallUserFuncRule($reflectionProvider, new FunctionCallParametersCheck(new RuleLevelHelper($reflectionProvider, true, false, true, true, false, false, true), new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true)); } #[RequiresPhp('>= 8.0')] diff --git a/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php index ecc2531fe4..540c35c1a7 100644 --- a/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ClosureAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php index 3b7253311e..468d8ee97f 100644 --- a/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/FunctionAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php b/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php index d6e6c46744..0bcd2e17cd 100644 --- a/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Functions/ParamAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Functions/data/bug-757.php b/tests/PHPStan/Rules/Functions/data/bug-757.php new file mode 100644 index 0000000000..a8e904b2f2 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-757.php @@ -0,0 +1,41 @@ +foo; + } + + public function getStringNoRef() : string { + return $this->foo; + } + + public static function &staticGetString() : string { + static $s = "bar"; + return $s; + } +} + +function &refFunction() : string { + static $s = "bar"; + return $s; +} + +function noRefFunction() : string { + return "bar"; +} + +function useString(string &$s) : void {} + +function () { + $a = new A(); + useString($a->getString()); // ok - returns by reference + useString($a->getStringNoRef()); // error - does not return by reference + useString(A::staticGetString()); // ok - returns by reference + useString(refFunction()); // ok - returns by reference + useString(noRefFunction()); // error - does not return by reference +}; diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php index 845667ef40..d3752ac401 100644 --- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php @@ -35,7 +35,7 @@ protected function getRule(): Rule $ruleLevelHelper = new RuleLevelHelper($reflectionProvider, $this->checkNullables, $this->checkThisOnly, $this->checkUnionTypes, $this->checkExplicitMixed, $this->checkImplicitMixed, false, true); return new CallMethodsRule( new MethodCallCheck($reflectionProvider, $ruleLevelHelper, true, true), - new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), true, true, true, true), + new FunctionCallParametersCheck($ruleLevelHelper, new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), $reflectionProvider, true, true, true, true), ); } diff --git a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php index 558607e8f5..9c28da3416 100644 --- a/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php +++ b/tests/PHPStan/Rules/Methods/CallStaticMethodsRuleTest.php @@ -53,6 +53,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php b/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php index 00ecb75183..2a11ad0cca 100644 --- a/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Methods/MethodAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php index a09e4e8f81..b2897ca63a 100644 --- a/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyAttributesRuleTest.php @@ -34,6 +34,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Properties/PropertyHookAttributesRuleTest.php b/tests/PHPStan/Rules/Properties/PropertyHookAttributesRuleTest.php index f1db640b3f..f55d2d67a7 100644 --- a/tests/PHPStan/Rules/Properties/PropertyHookAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/PropertyHookAttributesRuleTest.php @@ -32,6 +32,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, diff --git a/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php b/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php index 1a0ff65182..f621bb1531 100644 --- a/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php +++ b/tests/PHPStan/Rules/Traits/TraitAttributesRuleTest.php @@ -39,6 +39,7 @@ protected function getRule(): Rule new NullsafeCheck(), new UnresolvableTypeHelper(), new PropertyReflectionFinder(), + $reflectionProvider, true, true, true, From aced59d6b6062b37a707376ad1933f8ee161f99d Mon Sep 17 00:00:00 2001 From: phpstan-bot Date: Thu, 12 Feb 2026 14:51:02 +0000 Subject: [PATCH 2/2] Add regression test for #13711 Closes https://github.com/phpstan/phpstan/issues/13711 --- .../CallToFunctionParametersRuleTest.php | 5 +++++ .../Rules/Functions/data/bug-13711.php | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/PHPStan/Rules/Functions/data/bug-13711.php diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 9121d4b2c7..45692c1ea7 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -322,6 +322,11 @@ public function testBug757(): void ]); } + public function testBug13711(): void + { + $this->analyse([__DIR__ . '/data/bug-13711.php'], []); + } + public function testImplodeOnPhp74(): void { $errors = [ diff --git a/tests/PHPStan/Rules/Functions/data/bug-13711.php b/tests/PHPStan/Rules/Functions/data/bug-13711.php new file mode 100644 index 0000000000..dcb6800369 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-13711.php @@ -0,0 +1,20 @@ + */ + private array $array = []; + + /** @return array */ + public function &getList(): array + { + return $this->array; + } + + public function rewind(): void + { + reset($this->getList()); + } +}