1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-29 20:28:59 +01:00

Add more specific UndefinedMagicMethod issue

This commit is contained in:
Brown 2020-01-06 14:23:33 -05:00
parent 8e786a17dd
commit 083fbc55e1
5 changed files with 48 additions and 3 deletions

View File

@ -341,6 +341,7 @@
<xs:element name="UndefinedFunction" type="FunctionIssueHandlerType" minOccurs="0" />
<xs:element name="UndefinedInterface" type="ClassIssueHandlerType" minOccurs="0" />
<xs:element name="UndefinedInterfaceMethod" type="MethodIssueHandlerType" minOccurs="0" />
<xs:element name="UndefinedMagicMethod" type="MethodIssueHandlerType" minOccurs="0" />
<xs:element name="UndefinedMagicPropertyAssignment" type="PropertyIssueHandlerType" minOccurs="0" />
<xs:element name="UndefinedMagicPropertyFetch" type="PropertyIssueHandlerType" minOccurs="0" />
<xs:element name="UndefinedMethod" type="MethodIssueHandlerType" minOccurs="0" />

View File

@ -2304,6 +2304,22 @@ class C {}
interface I extends C {}
```
### UndefinedMagicMethod
Emitted when calling a magic method that doesnt exist
```php
/**
* @method bar():string
*/
class A {
public function __call(string $name, array $args) {
return "cool";
}
}
(new A)->foo();
```
### UndefinedMagicPropertyAssignment
Emitted when assigning a property on an object that doesnt have that magic property defined

View File

@ -27,6 +27,7 @@ use Psalm\Issue\PossiblyNullReference;
use Psalm\Issue\PossiblyUndefinedMethod;
use Psalm\Issue\PropertyTypeCoercion;
use Psalm\Issue\UndefinedInterfaceMethod;
use Psalm\Issue\UndefinedMagicMethod;
use Psalm\Issue\UndefinedMethod;
use Psalm\Issue\UndefinedThisPropertyAssignment;
use Psalm\Issue\UndefinedThisPropertyFetch;
@ -188,6 +189,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$non_existent_class_method_ids = [];
$non_existent_interface_method_ids = [];
$non_existent_magic_method_ids = [];
$existent_method_ids = [];
$has_mixed_method_call = false;
@ -228,7 +230,8 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$invalid_method_call_types,
$existent_method_ids,
$non_existent_class_method_ids,
$non_existent_interface_method_ids
$non_existent_interface_method_ids,
$non_existent_magic_method_ids
);
if ($result === false) {
@ -266,6 +269,21 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
}
}
if ($non_existent_magic_method_ids) {
if ($context->check_methods) {
if (IssueBuffer::accepts(
new UndefinedMagicMethod(
'Magic method ' . $non_existent_magic_method_ids[0] . ' does not exist',
new CodeLocation($source, $stmt->name),
$non_existent_magic_method_ids[0]
),
$statements_analyzer->getSuppressedIssues()
)) {
// keep going
}
}
}
if ($non_existent_class_method_ids) {
if ($context->check_methods) {
if ($existent_method_ids || $has_mixed_method_call) {
@ -417,6 +435,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
* @param array<string> &$existent_method_ids
* @param array<string> &$non_existent_class_method_ids
* @param array<string> &$non_existent_interface_method_ids
* @param array<string> &$non_existent_magic_method_ids
* @return null|bool
*/
private static function analyzeAtomicCall(
@ -436,6 +455,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
&$existent_method_ids,
&$non_existent_class_method_ids,
&$non_existent_interface_method_ids,
&$non_existent_magic_method_ids,
bool &$check_visibility = true
) {
$config = $codebase->config;
@ -638,6 +658,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
foreach ($intersection_types as $intersection_type) {
$i_non_existent_class_method_ids = [];
$i_non_existent_interface_method_ids = [];
$i_non_existent_magic_method_ids = [];
$intersection_return_type = null;
@ -658,6 +679,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$all_intersection_existent_method_ids,
$i_non_existent_class_method_ids,
$i_non_existent_interface_method_ids,
$i_non_existent_magic_method_ids,
$check_visibility
);
@ -801,7 +823,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
}
if ($class_storage->sealed_methods) {
$non_existent_class_method_ids[] = $method_id;
$non_existent_magic_method_ids[] = $method_id;
return true;
}
}

View File

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

View File

@ -591,7 +591,7 @@ class MagicMethodAnnotationTest extends TestCase
$child = new Child();
$child->getString();
$child->foo();',
'error_message' => 'UndefinedMethod - src' . DIRECTORY_SEPARATOR . 'somefile.php:13:29 - Method Child::foo does not exist',
'error_message' => 'UndefinedMagicMethod - src' . DIRECTORY_SEPARATOR . 'somefile.php:13:29 - Magic method Child::foo does not exist',
],
'annotationInvalidArg' => [
'<?php