1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +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="PossiblyInvalidArrayAccess" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidArrayAssignment" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyInvalidArrayAssignment" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidArrayOffset" 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="PossiblyInvalidMethodCall" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidPropertyAssignment" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyInvalidPropertyAssignment" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidPropertyFetch" 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. Emitted when its possible that the array offset is not applicable to the value youre trying to access.
```php ```php
$arr = rand(0, 5) > 2 ? ["a" => 5] : "hello"; $arr = rand(0, 1) ? ["a" => 5] : "hello";
echo $arr[0]; 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 ### PossiblyInvalidMethodCall
Emitted when trying to call a method on a value that may not be an object 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\PossiblyFalseArgument;
use Psalm\Issue\PossiblyFalseReference; use Psalm\Issue\PossiblyFalseReference;
use Psalm\Issue\PossiblyInvalidArgument; use Psalm\Issue\PossiblyInvalidArgument;
use Psalm\Issue\PossiblyInvalidFunctionCall;
use Psalm\Issue\PossiblyInvalidMethodCall; use Psalm\Issue\PossiblyInvalidMethodCall;
use Psalm\Issue\PossiblyNullArgument; use Psalm\Issue\PossiblyNullArgument;
use Psalm\Issue\PossiblyNullFunctionCall; 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) { foreach ($stmt->name->inferredType->types as $var_type_part) {
if ($var_type_part instanceof Type\Atomic\Fn) { if ($var_type_part instanceof Type\Atomic\Fn) {
$function_params = $var_type_part->params; $function_params = $var_type_part->params;
@ -182,11 +186,14 @@ class CallChecker
} }
$function_exists = true; $function_exists = true;
$has_valid_function_call_type = true;
} elseif ($var_type_part instanceof TMixed) { } elseif ($var_type_part instanceof TMixed) {
$has_valid_function_call_type = true;
// @todo maybe emit issue here // @todo maybe emit issue here
} elseif (($var_type_part instanceof TNamedObject && $var_type_part->value === 'Closure') || } elseif (($var_type_part instanceof TNamedObject && $var_type_part->value === 'Closure') ||
$var_type_part instanceof TCallable $var_type_part instanceof TCallable
) { ) {
$has_valid_function_call_type = true;
// this is fine // this is fine
} elseif ($var_type_part instanceof TNull) { } elseif ($var_type_part instanceof TNull) {
// handled above // handled above
@ -206,9 +213,27 @@ class CallChecker
$statements_checker $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( if (IssueBuffer::accepts(
new InvalidFunctionCall( 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) new CodeLocation($statements_checker->getSource(), $stmt)
), ),
$statements_checker->getSuppressedIssues() $statements_checker->getSuppressedIssues()

View File

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