mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Allow reference-returning functions to be passed as arguments of byref functions
This commit is contained in:
parent
d688b51534
commit
7fa541e39b
@ -1767,7 +1767,14 @@ class CallChecker
|
||||
$by_ref_type = $by_ref_type ? clone $by_ref_type : Type::getMixed();
|
||||
}
|
||||
|
||||
if ($by_ref && $by_ref_type) {
|
||||
if ($by_ref
|
||||
&& $by_ref_type
|
||||
&& !(
|
||||
$arg->value instanceof PhpParser\Node\Expr\ConstFetch
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\FuncCall
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\MethodCall
|
||||
)
|
||||
) {
|
||||
// special handling for array sort
|
||||
if ($argument_offset === 0
|
||||
&& $method_id
|
||||
@ -1991,9 +1998,16 @@ class CallChecker
|
||||
if ($arg->value instanceof PhpParser\Node\Scalar
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\Array_
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\ClassConstFetch
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\ConstFetch
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\FuncCall
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\MethodCall
|
||||
|| (
|
||||
(
|
||||
$arg->value instanceof PhpParser\Node\Expr\ConstFetch
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\FuncCall
|
||||
|| $arg->value instanceof PhpParser\Node\Expr\MethodCall
|
||||
) && (
|
||||
!isset($arg->value->inferredType)
|
||||
|| !$arg->value->inferredType->by_ref
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InvalidPassByReference(
|
||||
|
@ -1850,6 +1850,7 @@ class ExpressionChecker
|
||||
|
||||
$fleshed_out_type->from_docblock = $return_type->from_docblock;
|
||||
$fleshed_out_type->ignore_nullable_issues = $return_type->ignore_nullable_issues;
|
||||
$fleshed_out_type->by_ref = $return_type->by_ref;
|
||||
|
||||
return $fleshed_out_type;
|
||||
}
|
||||
|
@ -62,6 +62,11 @@ class FunctionLikeStorage
|
||||
*/
|
||||
public $variadic;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $returns_by_ref;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
|
@ -46,6 +46,13 @@ class Union
|
||||
*/
|
||||
public $ignore_nullable_issues = false;
|
||||
|
||||
/**
|
||||
* Whether or not the type was passed by reference
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $by_ref = false;
|
||||
|
||||
/** @var ?string */
|
||||
private $id;
|
||||
|
||||
|
@ -742,6 +742,10 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
|
||||
CodeLocation::FUNCTION_RETURN_TYPE
|
||||
);
|
||||
|
||||
if ($stmt->returnsByRef()) {
|
||||
$storage->return_type->by_ref = true;
|
||||
}
|
||||
|
||||
$storage->signature_return_type = $storage->return_type;
|
||||
$storage->signature_return_type_location = $storage->return_type_location;
|
||||
}
|
||||
@ -902,6 +906,10 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
|
||||
$storage->return_type->ignore_nullable_issues = true;
|
||||
}
|
||||
|
||||
if ($storage->return_type && $stmt->returnsByRef()) {
|
||||
$storage->return_type->by_ref = true;
|
||||
}
|
||||
|
||||
if ($docblock_info->return_type_line_number) {
|
||||
$storage->return_type_location->setCommentLine($docblock_info->return_type_line_number);
|
||||
}
|
||||
|
@ -31,6 +31,22 @@ class ReferenceConstraintTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'trackFunctionReturnRefs' => [
|
||||
'<?php
|
||||
class A {
|
||||
/** @var string */
|
||||
public $foo = "bar";
|
||||
|
||||
public function &getString() : string {
|
||||
return $this->foo;
|
||||
}
|
||||
}
|
||||
|
||||
function useString(string &$s) : void {}
|
||||
$a = new A();
|
||||
|
||||
useString($a->getString());',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user