mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
UnsupportedPropertyReferenceUsage
This commit is contained in:
parent
a4434f5fc9
commit
f41da745d1
@ -482,6 +482,7 @@
|
||||
<xs:element name="UnresolvableInclude" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnsafeGenericInstantiation" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnsafeInstantiation" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnsupportedPropertyReferenceUsage" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnsupportedReferenceUsage" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnusedBaselineEntry" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnusedClass" type="ClassIssueHandlerType" minOccurs="0" />
|
||||
|
@ -285,6 +285,7 @@
|
||||
- [UnresolvableInclude](issues/UnresolvableInclude.md)
|
||||
- [UnsafeGenericInstantiation](issues/UnsafeGenericInstantiation.md)
|
||||
- [UnsafeInstantiation](issues/UnsafeInstantiation.md)
|
||||
- [UnsupportedPropertyReferenceUsage](issues/UnsupportedPropertyReferenceUsage.md)
|
||||
- [UnsupportedReferenceUsage](issues/UnsupportedReferenceUsage.md)
|
||||
- [UnusedBaselineEntry](issues/UnusedBaselineEntry.md)
|
||||
- [UnusedClass](issues/UnusedClass.md)
|
||||
|
@ -0,0 +1,40 @@
|
||||
# UnsupportedPropertyReferenceUsage
|
||||
|
||||
Psalm cannot guarantee the soundness of code that uses references to properties.
|
||||
|
||||
### Examples of Uncaught Errors
|
||||
|
||||
* Instance property assigned wrong type:
|
||||
```php
|
||||
<?php
|
||||
class A {
|
||||
public int $b = 0;
|
||||
}
|
||||
$a = new A();
|
||||
$b = &$a->b;
|
||||
$b = ''; // Fatal error
|
||||
```
|
||||
|
||||
* Static property assigned wrong type:
|
||||
```php
|
||||
<?php
|
||||
class A {
|
||||
public static int $b = 0;
|
||||
}
|
||||
$b = &A::$b;
|
||||
$b = ''; // Fatal error
|
||||
```
|
||||
|
||||
* Readonly property reassigned:
|
||||
```php
|
||||
<?php
|
||||
class A {
|
||||
public function __construct(
|
||||
public readonly int $b,
|
||||
) {
|
||||
}
|
||||
}
|
||||
$a = new A(0);
|
||||
$b = &$a->b;
|
||||
$b = 1; // Fatal error
|
||||
```
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<files psalm-version="dev-master@88f6be1213950f29d6516eb422cf021b10bae455">
|
||||
<files psalm-version="dev-master@841cccd693a15da70c034a55eb05ee7ed8fdbc22">
|
||||
<file src="examples/TemplateChecker.php">
|
||||
<PossiblyUndefinedIntArrayOffset>
|
||||
<code><![CDATA[$comment_block->tags['variablesfrom'][0]]]></code>
|
||||
@ -114,6 +114,11 @@
|
||||
<code>$new_property_name</code>
|
||||
</PossiblyUndefinedIntArrayOffset>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php">
|
||||
<UnsupportedPropertyReferenceUsage>
|
||||
<code><![CDATA[$context->vars_in_scope[$lhs_var_id] = &$context->vars_in_scope[$rhs_var_id]]]></code>
|
||||
</UnsupportedPropertyReferenceUsage>
|
||||
</file>
|
||||
<file src="src/Psalm/Internal/Analyzer/Statements/Expression/BinaryOp/ArithmeticOpAnalyzer.php">
|
||||
<PossiblyUndefinedIntArrayOffset>
|
||||
<code>$invalid_left_messages[0]</code>
|
||||
|
@ -56,6 +56,7 @@ use Psalm\Issue\PossiblyUndefinedIntArrayOffset;
|
||||
use Psalm\Issue\ReferenceConstraintViolation;
|
||||
use Psalm\Issue\ReferenceReusedFromConfusingScope;
|
||||
use Psalm\Issue\UnnecessaryVarAnnotation;
|
||||
use Psalm\Issue\UnsupportedPropertyReferenceUsage;
|
||||
use Psalm\IssueBuffer;
|
||||
use Psalm\Node\Expr\BinaryOp\VirtualBitwiseAnd;
|
||||
use Psalm\Node\Expr\BinaryOp\VirtualBitwiseOr;
|
||||
@ -980,10 +981,18 @@ class AssignmentAnalyzer
|
||||
$context->references_to_external_scope[$lhs_var_id] = true;
|
||||
}
|
||||
if (strpos($rhs_var_id, '->') !== false) {
|
||||
IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage(
|
||||
new CodeLocation($statements_analyzer->getSource(), $stmt),
|
||||
));
|
||||
// Reference to object property, we always consider object properties to be an external scope for references
|
||||
// TODO handle differently so it's detected as unused if the object is unused?
|
||||
$context->references_to_external_scope[$lhs_var_id] = true;
|
||||
}
|
||||
if (strpos($rhs_var_id, '::') !== false) {
|
||||
IssueBuffer::maybeAdd(new UnsupportedPropertyReferenceUsage(
|
||||
new CodeLocation($statements_analyzer->getSource(), $stmt),
|
||||
));
|
||||
}
|
||||
|
||||
$lhs_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var);
|
||||
if (!$stmt->var instanceof ArrayDimFetch && !$stmt->var instanceof PropertyFetch) {
|
||||
|
21
src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php
Normal file
21
src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psalm\Issue;
|
||||
|
||||
use Psalm\CodeLocation;
|
||||
|
||||
final class UnsupportedPropertyReferenceUsage extends CodeIssue
|
||||
{
|
||||
public const ERROR_LEVEL = -1;
|
||||
public const SHORTCODE = 321;
|
||||
|
||||
public function __construct(CodeLocation $code_location)
|
||||
{
|
||||
parent::__construct(
|
||||
'This reference cannot be analyzed by Psalm.',
|
||||
$code_location,
|
||||
);
|
||||
}
|
||||
}
|
@ -2598,6 +2598,7 @@ class AssertAnnotationTest extends TestCase
|
||||
function requiresString(string $_str): void {}
|
||||
',
|
||||
'error_message' => 'NullArgument',
|
||||
'ignored_issues' => ['UnsupportedPropertyReferenceUsage'],
|
||||
],
|
||||
'assertionOnMagicPropertyWithoutMutationFreeGet' => [
|
||||
'code' => '<?php
|
||||
|
@ -209,6 +209,7 @@ class ReferenceTest extends TestCase
|
||||
'assertions' => [
|
||||
'$bar===' => "'bar'",
|
||||
],
|
||||
'ignored_issues' => ['UnsupportedPropertyReferenceUsage'],
|
||||
],
|
||||
'referenceReassignedInLoop' => [
|
||||
'code' => '<?php
|
||||
|
58
tests/UnsupportedPropertyReferenceUsage.php
Normal file
58
tests/UnsupportedPropertyReferenceUsage.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Psalm\Tests;
|
||||
|
||||
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
|
||||
|
||||
class UnsupportedPropertyReferenceUsage extends TestCase
|
||||
{
|
||||
use InvalidCodeAnalysisTestTrait;
|
||||
|
||||
public function providerInvalidCodeParse(): iterable
|
||||
{
|
||||
return [
|
||||
'instance property' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php
|
||||
class A {
|
||||
public int $b = 0;
|
||||
}
|
||||
$a = new A();
|
||||
$b = &$a->b;
|
||||
$b = ''; // Fatal error
|
||||
PHP,
|
||||
'error_message' => 'UnsupportedPropertyReferenceUsage',
|
||||
],
|
||||
'static property' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php
|
||||
class A {
|
||||
public static int $b = 0;
|
||||
}
|
||||
$b = &A::$b;
|
||||
$b = ''; // Fatal error
|
||||
PHP,
|
||||
'error_message' => 'UnsupportedPropertyReferenceUsage',
|
||||
],
|
||||
'readonly property' => [
|
||||
'code' => <<<'PHP'
|
||||
<?php
|
||||
class A {
|
||||
public function __construct(
|
||||
public readonly int $b,
|
||||
) {
|
||||
}
|
||||
}
|
||||
$a = new A(0);
|
||||
$b = &$a->b;
|
||||
$b = 1; // Fatal error
|
||||
PHP,
|
||||
'error_message' => 'UnsupportedPropertyReferenceUsage',
|
||||
'error_levels' => [],
|
||||
'php_version' => '8.1',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@ -1325,6 +1325,8 @@ class UnusedVariableTest extends TestCase
|
||||
$update = $value;
|
||||
}
|
||||
}',
|
||||
'assertions' => [],
|
||||
'ignored_issues' => ['UnsupportedPropertyReferenceUsage'],
|
||||
],
|
||||
'createdAndUsedInCondition' => [
|
||||
'code' => '<?php
|
||||
|
Loading…
Reference in New Issue
Block a user