1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Add PossibyInvalidFunctionCall, emitted when function call may not be valid

This commit is contained in:
Matthew Brown 2018-01-01 12:00:02 -05:00
parent 5afe3b10fa
commit 7418d6685f
4 changed files with 43 additions and 2 deletions

View File

@ -172,6 +172,7 @@
<xs:element name="PossiblyInvalidArrayAccess" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidArrayAssignment" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidArrayOffset" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidFunctionCall" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidMethodCall" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidPropertyAssignment" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidPropertyFetch" type="IssueHandlerType" minOccurs="0" />

View File

@ -881,10 +881,19 @@ $arr[0] = "hello";
Emitted when its possible that the array offset is not applicable to the value youre trying to access.
```php
$arr = rand(0, 5) > 2 ? ["a" => 5] : "hello";
$arr = rand(0, 1) ? ["a" => 5] : "hello";
echo $arr[0];
```
### PossiblyInvalidFunctionCall
Emitted when trying to call a function on a value that may not be callable
```php
$a = rand(0, 1) ? 5 : function() : int { return 5; };
$b = $a();
```
### PossiblyInvalidMethodCall
Emitted when trying to call a method on a value that may not be an object

View File

@ -36,6 +36,7 @@ use Psalm\Issue\ParentNotFound;
use Psalm\Issue\PossiblyFalseArgument;
use Psalm\Issue\PossiblyFalseReference;
use Psalm\Issue\PossiblyInvalidArgument;
use Psalm\Issue\PossiblyInvalidFunctionCall;
use Psalm\Issue\PossiblyInvalidMethodCall;
use Psalm\Issue\PossiblyNullArgument;
use Psalm\Issue\PossiblyNullFunctionCall;
@ -168,6 +169,9 @@ class CallChecker
}
}
$invalid_function_call_types = [];
$has_valid_function_call_type = false;
foreach ($stmt->name->inferredType->types as $var_type_part) {
if ($var_type_part instanceof Type\Atomic\Fn) {
$function_params = $var_type_part->params;
@ -182,11 +186,14 @@ class CallChecker
}
$function_exists = true;
$has_valid_function_call_type = true;
} elseif ($var_type_part instanceof TMixed) {
$has_valid_function_call_type = true;
// @todo maybe emit issue here
} elseif (($var_type_part instanceof TNamedObject && $var_type_part->value === 'Closure') ||
$var_type_part instanceof TCallable
) {
$has_valid_function_call_type = true;
// this is fine
} elseif ($var_type_part instanceof TNull) {
// handled above
@ -206,9 +213,27 @@ class CallChecker
$statements_checker
);
$invalid_function_call_types[] = (string)$var_type_part;
}
}
if ($invalid_function_call_types) {
$var_type_part = reset($invalid_function_call_types);
if ($has_valid_function_call_type) {
if (IssueBuffer::accepts(
new PossiblyInvalidFunctionCall(
'Cannot treat type ' . $var_type_part . ' as callable',
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
} else {
if (IssueBuffer::accepts(
new InvalidFunctionCall(
'Cannot treat ' . $var_id . ' of type ' . $var_type_part . ' as function',
'Cannot treat type ' . $var_type_part . ' as callable',
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()

View File

@ -0,0 +1,6 @@
<?php
namespace Psalm\Issue;
class PossiblyInvalidFunctionCall extends CodeError
{
}