Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UnsupportedPropertyReferenceUsage #9769

Merged
merged 1 commit into from May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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