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

Fix #299 - add PossiblyInvalidMethodCall

This commit is contained in:
Matt Brown 2017-11-15 11:34:40 -05:00
parent 9111b1c725
commit c5faa2d06a
4 changed files with 61 additions and 9 deletions

View File

@ -158,6 +158,8 @@
<xs:element name="PossiblyFalseReference" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyFalseReference" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidArgument" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyInvalidArgument" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidArrayAccess" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyInvalidArrayAccess" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidMethodCall" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyInvalidPropertyAssignment" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyNullArgument" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyNullArgument" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyNullArrayAccess" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyNullArrayAccess" type="IssueHandlerType" minOccurs="0" />
<xs:element name="PossiblyNullFunctionCall" type="IssueHandlerType" minOccurs="0" /> <xs:element name="PossiblyNullFunctionCall" type="IssueHandlerType" minOccurs="0" />

View File

@ -35,6 +35,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\PossiblyInvalidMethodCall;
use Psalm\Issue\PossiblyNullArgument; use Psalm\Issue\PossiblyNullArgument;
use Psalm\Issue\PossiblyNullFunctionCall; use Psalm\Issue\PossiblyNullFunctionCall;
use Psalm\Issue\PossiblyNullReference; use Psalm\Issue\PossiblyNullReference;
@ -764,6 +765,9 @@ class CallChecker
$non_existent_method_ids = []; $non_existent_method_ids = [];
$existent_method_ids = []; $existent_method_ids = [];
$invalid_method_call_types = [];
$has_valid_method_call_type = false;
$code_location = new CodeLocation($source, $stmt); $code_location = new CodeLocation($source, $stmt);
if ($class_type && is_string($stmt->name)) { if ($class_type && is_string($stmt->name)) {
@ -782,15 +786,7 @@ class CallChecker
case 'Psalm\\Type\\Atomic\\TArray': case 'Psalm\\Type\\Atomic\\TArray':
case 'Psalm\\Type\\Atomic\\TString': case 'Psalm\\Type\\Atomic\\TString':
case 'Psalm\\Type\\Atomic\\TNumericString': case 'Psalm\\Type\\Atomic\\TNumericString':
if (IssueBuffer::accepts( $invalid_method_call_types[] = (string)$class_type_part;
new InvalidMethodCall(
'Cannot call method ' . $stmt->name . ' on ' . $class_type . ' variable ' . $var_id,
$code_location
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
break; break;
case 'Psalm\\Type\\Atomic\\TMixed': case 'Psalm\\Type\\Atomic\\TMixed':
@ -810,6 +806,8 @@ class CallChecker
continue; continue;
} }
$has_valid_method_call_type = true;
$fq_class_name = $class_type_part->value; $fq_class_name = $class_type_part->value;
$intersection_types = $class_type_part->getIntersectionTypes(); $intersection_types = $class_type_part->getIntersectionTypes();
@ -1030,6 +1028,32 @@ class CallChecker
} }
} }
if ($invalid_method_call_types) {
$class_type = $invalid_method_call_types[0];
if ($has_valid_method_call_type) {
if (IssueBuffer::accepts(
new PossiblyInvalidMethodCall(
'Cannot call method on possible ' . $class_type . ' variable ' . $var_id,
$code_location
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
} else {
if (IssueBuffer::accepts(
new InvalidMethodCall(
'Cannot call method on ' . $class_type . ' variable ' . $var_id,
$code_location
),
$statements_checker->getSuppressedIssues()
)) {
return false;
}
}
}
if ($non_existent_method_ids) { if ($non_existent_method_ids) {
if ($existent_method_ids) { if ($existent_method_ids) {
if (IssueBuffer::accepts( if (IssueBuffer::accepts(

View File

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

View File

@ -118,6 +118,26 @@ class MethodCallTest extends TestCase
'MixedAssignment', 'MixedAssignment',
], ],
], ],
'invalidMethodCall' => [
'<?php
("hello")->someMethod();',
'error_message' => 'InvalidMethodCall',
],
'possiblyInvalidMethodCall' => [
'<?php
class A1 {
public function methodOfA(): void {
}
}
/** @param A1|string $x */
function example($x, bool $isObject) {
if ($isObject) {
$x->methodOfA();
}
}',
'error_message' => 'PossiblyInvalidMethodCall',
],
'selfNonStaticInvocation' => [ 'selfNonStaticInvocation' => [
'<?php '<?php
class A { class A {