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

Fix #300 - add PossiblyInvalidPropertyFetch

This commit is contained in:
Matt Brown 2017-11-15 11:44:13 -05:00
parent c5faa2d06a
commit a99135c4d0
4 changed files with 46 additions and 9 deletions

View File

@ -160,6 +160,7 @@
<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="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="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

@ -27,6 +27,7 @@ use Psalm\Issue\NullPropertyFetch;
use Psalm\Issue\NullReference; use Psalm\Issue\NullReference;
use Psalm\Issue\ParentNotFound; use Psalm\Issue\ParentNotFound;
use Psalm\Issue\PossiblyInvalidArrayAccess; use Psalm\Issue\PossiblyInvalidArrayAccess;
use Psalm\Issue\PossiblyInvalidPropertyFetch;
use Psalm\Issue\PossiblyNullArrayAccess; use Psalm\Issue\PossiblyNullArrayAccess;
use Psalm\Issue\PossiblyNullPropertyFetch; use Psalm\Issue\PossiblyNullPropertyFetch;
use Psalm\Issue\PossiblyNullReference; use Psalm\Issue\PossiblyNullReference;
@ -167,25 +168,22 @@ class FetchChecker
return null; return null;
} }
$invalid_fetch_types = [];
$has_valid_fetch_type = false;
foreach ($stmt_var_type->types as $lhs_type_part) { foreach ($stmt_var_type->types as $lhs_type_part) {
if ($lhs_type_part instanceof TNull) { if ($lhs_type_part instanceof TNull) {
continue; continue;
} }
if (!$lhs_type_part instanceof TNamedObject && !$lhs_type_part instanceof TObject) { if (!$lhs_type_part instanceof TNamedObject && !$lhs_type_part instanceof TObject) {
if (IssueBuffer::accepts( $invalid_fetch_types[] = (string)$lhs_type_part;
new InvalidPropertyFetch(
'Cannot fetch property on non-object ' . $stmt_var_id . ' of type ' . $lhs_type_part,
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
// fall through
}
continue; continue;
} }
$has_valid_fetch_type = true;
// stdClass and SimpleXMLElement are special cases where we cannot infer the return types // stdClass and SimpleXMLElement are special cases where we cannot infer the return types
// but we don't want to throw an error // but we don't want to throw an error
// Hack has a similar issue: https://github.com/facebook/hhvm/issues/5164 // Hack has a similar issue: https://github.com/facebook/hhvm/issues/5164
@ -365,6 +363,32 @@ class FetchChecker
} }
} }
if ($invalid_fetch_types) {
$lhs_type_part = $invalid_fetch_types[0];
if ($has_valid_fetch_type) {
if (IssueBuffer::accepts(
new PossiblyInvalidPropertyFetch(
'Cannot fetch property on possible non-object ' . $stmt_var_id . ' of type ' . $lhs_type_part,
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
// fall through
}
} else {
if (IssueBuffer::accepts(
new InvalidPropertyFetch(
'Cannot fetch property on non-object ' . $stmt_var_id . ' of type ' . $lhs_type_part,
new CodeLocation($statements_checker->getSource(), $stmt)
),
$statements_checker->getSuppressedIssues()
)) {
// fall through
}
}
}
if ($var_id) { if ($var_id) {
$context->vars_in_scope[$var_id] = isset($stmt->inferredType) ? $stmt->inferredType : Type::getMixed(); $context->vars_in_scope[$var_id] = isset($stmt->inferredType) ? $stmt->inferredType : Type::getMixed();
} }

View File

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

View File

@ -609,6 +609,12 @@ final class B extends A {}',
echo $a->foo;', echo $a->foo;',
'error_message' => 'InvalidPropertyFetch', 'error_message' => 'InvalidPropertyFetch',
], ],
'possiblyBadFetch' => [
'<?php
$a = rand(0, 5) > 3 ? "hello" : new stdClass;
echo $a->foo;',
'error_message' => 'PossiblyInvalidPropertyFetch',
],
'mixedPropertyFetch' => [ 'mixedPropertyFetch' => [
'<?php '<?php
class Foo { class Foo {