Skip to content

Commit

Permalink
UnsupportedPropertyReferenceUsage
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-worman committed May 11, 2023
1 parent 5661ea6 commit 47b013b
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 1 deletion.
1 change: 1 addition & 0 deletions config.xsd
Expand Up @@ -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" />
Expand Down
1 change: 1 addition & 0 deletions docs/running_psalm/issues.md
Expand Up @@ -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)
Expand Down
40 changes: 40 additions & 0 deletions docs/running_psalm/issues/UnsupportedPropertyReferenceUsage.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
```
7 changes: 6 additions & 1 deletion psalm-baseline.xml
@@ -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>
Expand Down Expand Up @@ -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>
Expand Down
Expand Up @@ -56,6 +56,7 @@
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;
Expand Down Expand Up @@ -980,10 +981,18 @@ public static function analyzeAssignmentRef(
$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) {
Expand Down
21 changes: 21 additions & 0 deletions src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php
@@ -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,
);
}
}
1 change: 1 addition & 0 deletions tests/AssertAnnotationTest.php
Expand Up @@ -2598,6 +2598,7 @@ function assertBarNotNull(Foo $foo): bool
function requiresString(string $_str): void {}
',
'error_message' => 'NullArgument',
'ignored_issues' => ['UnsupportedPropertyReferenceUsage'],
],
'assertionOnMagicPropertyWithoutMutationFreeGet' => [
'code' => '<?php
Expand Down
1 change: 1 addition & 0 deletions tests/ReferenceTest.php
Expand Up @@ -209,6 +209,7 @@ class Foo
'assertions' => [
'$bar===' => "'bar'",
],
'ignored_issues' => ['UnsupportedPropertyReferenceUsage'],
],
'referenceReassignedInLoop' => [
'code' => '<?php
Expand Down
58 changes: 58 additions & 0 deletions tests/UnsupportedPropertyReferenceUsage.php
@@ -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',
],
];
}
}
2 changes: 2 additions & 0 deletions tests/UnusedVariableTest.php
Expand Up @@ -1325,6 +1325,8 @@ public function writeByRef(string $value): void {
$update = $value;
}
}',
'assertions' => [],
'ignored_issues' => ['UnsupportedPropertyReferenceUsage'],
],
'createdAndUsedInCondition' => [
'code' => '<?php
Expand Down

0 comments on commit 47b013b

Please sign in to comment.