From 07f4045ccdb7c327bc9cbe036ce0f6fdee008f15 Mon Sep 17 00:00:00 2001 From: Evan Shaw Date: Sat, 3 Feb 2024 13:06:12 +1300 Subject: [PATCH 1/2] Add InvalidOverride issue --- config.xsd | 1 + docs/running_psalm/error_levels.md | 1 + docs/running_psalm/issues.md | 1 + docs/running_psalm/issues/InvalidOverride.md | 24 ++++++++++++++++++++ src/Psalm/Issue/InvalidOverride.php | 9 ++++++++ tests/DocumentationTest.php | 4 ++++ 6 files changed, 40 insertions(+) create mode 100644 docs/running_psalm/issues/InvalidOverride.md create mode 100644 src/Psalm/Issue/InvalidOverride.php diff --git a/config.xsd b/config.xsd index 0f3e88916c8..4cdb3298e7d 100644 --- a/config.xsd +++ b/config.xsd @@ -283,6 +283,7 @@ + diff --git a/docs/running_psalm/error_levels.md b/docs/running_psalm/error_levels.md index f3df22adb45..923a36eef57 100644 --- a/docs/running_psalm/error_levels.md +++ b/docs/running_psalm/error_levels.md @@ -98,6 +98,7 @@ Level 5 and above allows a more non-verifiable code, and higher levels are even - [CircularReference](issues/CircularReference.md) - [ConflictingReferenceConstraint](issues/ConflictingReferenceConstraint.md) - [ContinueOutsideLoop](issues/ContinueOutsideLoop.md) +- [InvalidOverride](issues/InvalidOverride.md) - [InvalidTypeImport](issues/InvalidTypeImport.md) - [MethodSignatureMismatch](issues/MethodSignatureMismatch.md) - [OverriddenMethodAccess](issues/OverriddenMethodAccess.md) diff --git a/docs/running_psalm/issues.md b/docs/running_psalm/issues.md index 179f9bf7b53..5f34274acc8 100644 --- a/docs/running_psalm/issues.md +++ b/docs/running_psalm/issues.md @@ -84,6 +84,7 @@ - [InvalidNamedArgument](issues/InvalidNamedArgument.md) - [InvalidNullableReturnType](issues/InvalidNullableReturnType.md) - [InvalidOperand](issues/InvalidOperand.md) + - [InvalidOverride](issues/InvalidOverride.md) - [InvalidParamDefault](issues/InvalidParamDefault.md) - [InvalidParent](issues/InvalidParent.md) - [InvalidPassByReference](issues/InvalidPassByReference.md) diff --git a/docs/running_psalm/issues/InvalidOverride.md b/docs/running_psalm/issues/InvalidOverride.md new file mode 100644 index 00000000000..a93f14b8f71 --- /dev/null +++ b/docs/running_psalm/issues/InvalidOverride.md @@ -0,0 +1,24 @@ +# InvalidOverride + +Emitted when an `Override` attribute was added to a method that does not override a method from a parent class or implemented interface. + +```php + Date: Sat, 3 Feb 2024 18:30:59 +1300 Subject: [PATCH 2/2] Emit InvalidOverride --- .../Analyzer/FunctionLikeAnalyzer.php | 19 +++++ tests/AttributeTest.php | 79 +++++++++++++++++-- 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php index bf4378d9158..964b6495148 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php @@ -31,6 +31,7 @@ use Psalm\Internal\Type\TemplateStandinTypeReplacer; use Psalm\Internal\Type\TypeExpander; use Psalm\Issue\InvalidDocblockParamName; +use Psalm\Issue\InvalidOverride; use Psalm\Issue\InvalidParamDefault; use Psalm\Issue\InvalidThrow; use Psalm\Issue\MethodSignatureMismatch; @@ -48,6 +49,7 @@ use Psalm\Node\Expr\VirtualVariable; use Psalm\Node\Stmt\VirtualWhile; use Psalm\Plugin\EventHandler\Event\AfterFunctionLikeAnalysisEvent; +use Psalm\Storage\AttributeStorage; use Psalm\Storage\ClassLikeStorage; use Psalm\Storage\FunctionLikeParameter; use Psalm\Storage\FunctionLikeStorage; @@ -65,6 +67,7 @@ use function array_combine; use function array_diff_key; +use function array_filter; use function array_key_exists; use function array_keys; use function array_merge; @@ -1970,6 +1973,22 @@ private function getFunctionInformation( true, ); + if ($codebase->analysis_php_version_id >= 8_03_00 + && (!$overridden_method_ids || $storage->cased_name === '__construct') + && array_filter( + $storage->attributes, + static fn(AttributeStorage $s): bool => $s->fq_class_name === 'Override', + ) + ) { + IssueBuffer::maybeAdd( + new InvalidOverride( + 'Method ' . $storage->cased_name . ' does not match any parent method', + $codeLocation, + ), + $this->getSuppressedIssues(), + ); + } + if ($overridden_method_ids && !$context->collect_initializations && !$context->collect_mutations diff --git a/tests/AttributeTest.php b/tests/AttributeTest.php index ddb5b1f5fd9..4a631c5b3dd 100644 --- a/tests/AttributeTest.php +++ b/tests/AttributeTest.php @@ -295,14 +295,28 @@ class Foo ], 'override' => [ 'code' => ' [], + 'ignored_issues' => [], + 'php_version' => '8.3', + ], + 'overrideInterface' => [ + 'code' => ' [], @@ -527,6 +541,61 @@ function foo() : void {}', function foo(#[Pure] string $str) : void {}', 'error_message' => 'UndefinedAttributeClass - src' . DIRECTORY_SEPARATOR . 'somefile.php:4:36', ], + 'overrideWithNoParent' => [ + 'code' => ' 'InvalidOverride - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:25', + 'error_levels' => [], + 'php_version' => '8.3', + ], + 'overrideConstructor' => [ + 'code' => ' 'InvalidOverride - src' . DIRECTORY_SEPARATOR . 'somefile.php:10:25', + 'error_levels' => [], + 'php_version' => '8.3', + ], + 'overridePrivate' => [ + 'code' => ' 'InvalidOverride - src' . DIRECTORY_SEPARATOR . 'somefile.php:7:25', + 'error_levels' => [], + 'php_version' => '8.3', + ], + 'overrideInterfaceWithNoParent' => [ + 'code' => ' 'InvalidOverride - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:25', + 'error_levels' => [], + 'php_version' => '8.3', + ], 'tooFewArgumentsToAttributeConstructor' => [ 'code' => '