diff --git a/config.xsd b/config.xsd index 99e0fde33..4d4f377f8 100644 --- a/config.xsd +++ b/config.xsd @@ -482,6 +482,7 @@ + diff --git a/docs/running_psalm/issues.md b/docs/running_psalm/issues.md index d0e745b38..d9b3b4f16 100644 --- a/docs/running_psalm/issues.md +++ b/docs/running_psalm/issues.md @@ -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) diff --git a/docs/running_psalm/issues/UnsupportedPropertyReferenceUsage.md b/docs/running_psalm/issues/UnsupportedPropertyReferenceUsage.md new file mode 100644 index 000000000..60da066d5 --- /dev/null +++ b/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 +b; +$b = ''; // Fatal error +``` + +* Static property assigned wrong type: +```php +b; +$b = 1; // Fatal error +``` diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 70c788cbd..69c518581 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,5 @@ - + tags['variablesfrom'][0]]]> @@ -114,6 +114,11 @@ $new_property_name + + + vars_in_scope[$lhs_var_id] = &$context->vars_in_scope[$rhs_var_id]]]> + + $invalid_left_messages[0] diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php index 6f0053468..509acb41a 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/AssignmentAnalyzer.php @@ -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) { diff --git a/src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php b/src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php new file mode 100644 index 000000000..a0b0e9d80 --- /dev/null +++ b/src/Psalm/Issue/UnsupportedPropertyReferenceUsage.php @@ -0,0 +1,21 @@ + 'NullArgument', + 'ignored_issues' => ['UnsupportedPropertyReferenceUsage'], ], 'assertionOnMagicPropertyWithoutMutationFreeGet' => [ 'code' => ' [ '$bar===' => "'bar'", ], + 'ignored_issues' => ['UnsupportedPropertyReferenceUsage'], ], 'referenceReassignedInLoop' => [ 'code' => ' [ + 'code' => <<<'PHP' + b; + $b = ''; // Fatal error + PHP, + 'error_message' => 'UnsupportedPropertyReferenceUsage', + ], + 'static property' => [ + 'code' => <<<'PHP' + 'UnsupportedPropertyReferenceUsage', + ], + 'readonly property' => [ + 'code' => <<<'PHP' + b; + $b = 1; // Fatal error + PHP, + 'error_message' => 'UnsupportedPropertyReferenceUsage', + 'error_levels' => [], + 'php_version' => '8.1', + ], + ]; + } +} diff --git a/tests/UnusedVariableTest.php b/tests/UnusedVariableTest.php index 028dfc6b2..57f1a425d 100644 --- a/tests/UnusedVariableTest.php +++ b/tests/UnusedVariableTest.php @@ -1325,6 +1325,8 @@ class UnusedVariableTest extends TestCase $update = $value; } }', + 'assertions' => [], + 'ignored_issues' => ['UnsupportedPropertyReferenceUsage'], ], 'createdAndUsedInCondition' => [ 'code' => '