diff --git a/config.xsd b/config.xsd index de492fcb1da..211e6e151ab 100644 --- a/config.xsd +++ b/config.xsd @@ -230,6 +230,7 @@ + diff --git a/docs/running_psalm/error_levels.md b/docs/running_psalm/error_levels.md index 35c4821d63b..9bb001277c3 100644 --- a/docs/running_psalm/error_levels.md +++ b/docs/running_psalm/error_levels.md @@ -29,6 +29,7 @@ Level 5 and above allows a more non-verifiable code, and higher levels are even - [DuplicateFunction](issues/DuplicateFunction.md) - [DuplicateMethod](issues/DuplicateMethod.md) - [DuplicateParam](issues/DuplicateParam.md) + - [DuplicateProperty](issues/DuplicateProperty.md) - [EmptyArrayAccess](issues/EmptyArrayAccess.md) - [ExtensionRequirementViolation](issues/ExtensionRequirementViolation.md) - [ImplementationRequirementViolation](issues/ImplementationRequirementViolation.md) diff --git a/docs/running_psalm/issues.md b/docs/running_psalm/issues.md index c14cecd1451..f2655635cf1 100644 --- a/docs/running_psalm/issues.md +++ b/docs/running_psalm/issues.md @@ -31,6 +31,7 @@ - [DuplicateFunction](issues/DuplicateFunction.md) - [DuplicateMethod](issues/DuplicateMethod.md) - [DuplicateParam](issues/DuplicateParam.md) + - [DuplicateProperty](issues/DuplicateProperty.md) - [EmptyArrayAccess](issues/EmptyArrayAccess.md) - [ExtensionRequirementViolation](issues/ExtensionRequirementViolation.md) - [FalsableReturnStatement](issues/FalsableReturnStatement.md) diff --git a/docs/running_psalm/issues/DuplicateProperty.md b/docs/running_psalm/issues/DuplicateProperty.md new file mode 100644 index 00000000000..1a7cf0e6e59 --- /dev/null +++ b/docs/running_psalm/issues/DuplicateProperty.md @@ -0,0 +1,19 @@ +# DuplicateProperty + +Emitted when a class property is defined twice + +```php +props as $property) { $doc_var_location = null; + if (isset($storage->properties[$property->name->name])) { + IssueBuffer::maybeAdd( + new DuplicateProperty( + 'Property ' . $fq_classlike_name . '::$' . $property->name->name . ' has already been defined', + new CodeLocation($this->file_scanner, $stmt, null, true), + $fq_classlike_name . '::$' . $property->name->name, + ), + ); + } + $property_storage = $storage->properties[$property->name->name] = new PropertyStorage(); $property_storage->is_static = $stmt->isStatic(); $property_storage->type = $signature_type; diff --git a/src/Psalm/Issue/DuplicateProperty.php b/src/Psalm/Issue/DuplicateProperty.php new file mode 100644 index 00000000000..89538730a7d --- /dev/null +++ b/src/Psalm/Issue/DuplicateProperty.php @@ -0,0 +1,9 @@ + 'InheritorViolation', 'ignored_issues' => [], ], + 'duplicateInstanceProperties' => [ + 'code' => <<<'PHP' + 'DuplicateProperty', + 'ignored_issues' => [], + ], + 'duplicateStaticProperties' => [ + 'code' => <<<'PHP' + 'DuplicateProperty', + 'ignored_issues' => [], + ], + 'duplicateMixedProperties' => [ + 'code' => <<<'PHP' + 'DuplicateProperty', + 'ignored_issues' => [], + ], + 'duplicatePropertiesDifferentVisibility' => [ + 'code' => <<<'PHP' + 'DuplicateProperty', + 'ignored_issues' => [], + ], ]; } } diff --git a/tests/TraitTest.php b/tests/TraitTest.php index bd53bd603c8..4b04b7c4e31 100644 --- a/tests/TraitTest.php +++ b/tests/TraitTest.php @@ -1236,6 +1236,15 @@ trait A { const B = 0; } 'ignored_issues' => [], 'php_version' => '8.1', ], + 'duplicateTraitProperty' => [ + 'code' => ' 'DuplicateProperty', + ], ]; } }