1
0
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:
Matthew Brown 2018-01-11 23:18:13 -05:00
parent d688b51534
commit 7fa541e39b
6 changed files with 55 additions and 4 deletions

View File

@ -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(

View File

@ -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;
}

View File

@ -62,6 +62,11 @@ class FunctionLikeStorage
*/
public $variadic;
/**
* @var bool
*/
public $returns_by_ref;
/**
* @var bool
*/

View File

@ -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;

View File

@ -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);
}

View File

@ -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());',
],
];
}