1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Prevent pass by ref when type type is given

This commit is contained in:
Brown 2019-02-20 17:43:12 -05:00
parent d2968081f8
commit 079ac44263
6 changed files with 50 additions and 7 deletions

View File

@ -104,6 +104,9 @@ class ReturnTypeAnalyzer
/** @var PhpParser\Node\Stmt[] */
$function_stmts = $function->getStmts();
$ignore_nullable_issues = false;
$ignore_falsable_issues = false;
$inferred_return_type_parts = ReturnTypeCollector::getReturnTypes(
$function_stmts,
$inferred_yield_types,

View File

@ -24,9 +24,9 @@ class ReturnTypeCollector
public static function getReturnTypes(
array $stmts,
array &$yield_types,
&$ignore_nullable_issues = false,
&$ignore_falsable_issues = false,
$collapse_types = false
bool &$ignore_nullable_issues = false,
bool &$ignore_falsable_issues = false,
bool $collapse_types = false
) {
$return_types = [];

View File

@ -630,6 +630,9 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer implements Statements
$closure_yield_types = [];
$ignore_nullable_issues = false;
$ignore_falsable_issues = false;
$closure_return_types = ReturnTypeCollector::getReturnTypes(
$this->function->stmts,
$closure_yield_types,

View File

@ -1294,7 +1294,8 @@ class CallAnalyzer
$arg->value,
$by_ref_type,
$context,
$method_id && (strpos($method_id, '::') !== false || !CallMap::inCallMap($method_id))
$method_id && (strpos($method_id, '::') !== false || !CallMap::inCallMap($method_id)),
true
);
}
}

View File

@ -632,7 +632,8 @@ class ExpressionAnalyzer
PhpParser\Node\Expr $stmt,
Type\Union $by_ref_type,
Context $context,
$constrain_type = true
bool $constrain_type = true,
bool $prevent_null = false
) {
$var_id = self::getVarId(
$stmt,
@ -652,6 +653,24 @@ class ExpressionAnalyzer
$location = new CodeLocation($statements_analyzer, $stmt);
$statements_analyzer->registerVariable($var_id, $location, null);
if ($constrain_type
&& $prevent_null
&& !$by_ref_type->isMixed()
&& !$by_ref_type->isNullable()
&& !strpos($var_id, '->')
&& !strpos($var_id, '::')
) {
if (IssueBuffer::accepts(
new \Psalm\Issue\NullArgument(
'Not expecting null argument passed by reference',
new CodeLocation($statements_analyzer->getSource(), $stmt)
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
}
if ($context->collect_references) {
$context->unreferenced_vars[$var_id] = [$location->getHash() => $location];
}

View File

@ -113,7 +113,7 @@ class FunctionCallTest extends TestCase
],
'byRefNewString' => [
'<?php
function fooFoo(string &$v): void {}
function fooFoo(?string &$v): void {}
fooFoo($a);',
],
'byRefVariableFunctionExistingArray' => [
@ -1452,7 +1452,15 @@ class FunctionCallTest extends TestCase
],
[],
'7.3'
]
],
'nullableByRef' => [
'<?php
function foo(?string &$s) : void {}
function bar() : void {
foo($bar);
}'
],
];
}
@ -1936,6 +1944,15 @@ class FunctionCallTest extends TestCase
accepts(arr());',
'error_message' => 'InvalidArgument',
],
'nonNullableByRef' => [
'<?php
function foo(string &$s) : void {}
function bar() : void {
foo($bar);
}',
'error_message' => 'NullArgument',
],
];
}
}