diff --git a/build/target-repository/docs/rector_rules_overview.md b/build/target-repository/docs/rector_rules_overview.md
index 3f6fa376392..7b136074996 100644
--- a/build/target-repository/docs/rector_rules_overview.md
+++ b/build/target-repository/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# 355 Rules Overview
+# 356 Rules Overview
@@ -44,6 +44,8 @@
- [Php82](#php82) (4)
+- [Php83](#php83) (1)
+
- [Privatization](#privatization) (4)
- [Removing](#removing) (5)
@@ -5314,6 +5316,33 @@ Change deprecated utf8_decode and utf8_encode to mb_convert_encoding
+## Php83
+
+### AddOverrideAttributeToOverriddenMethodsRector
+
+Add override attribute to overridden methods
+
+- class: [`Rector\Php83\Rector\ClassMethod\AddOverrideAttributeToOverriddenMethodsRector`](../rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php)
+
+```diff
+ class ParentClass
+ {
+ public function foo()
+ {
+ }
+ }
+
+ class ChildClass extends ParentClass
+ {
++ #[\Override]
+ public function foo()
+ {
+ }
+ }
+```
+
+
+
## Privatization
### FinalizeClassesWithoutChildrenRector
diff --git a/config/set/level/up-to-php83.php b/config/set/level/up-to-php83.php
new file mode 100644
index 00000000000..d30c096fbdb
--- /dev/null
+++ b/config/set/level/up-to-php83.php
@@ -0,0 +1,15 @@
+sets([SetList::PHP_83, LevelSetList::UP_TO_PHP_82]);
+
+ // parameter must be defined after import, to override imported param version
+ $rectorConfig->phpVersion(PhpVersion::PHP_83);
+};
diff --git a/config/set/php83.php b/config/set/php83.php
new file mode 100644
index 00000000000..474fd7d2d4f
--- /dev/null
+++ b/config/set/php83.php
@@ -0,0 +1,10 @@
+rules([AddOverrideAttributeToOverriddenMethodsRector::class]);
+};
diff --git a/packages/Set/ValueObject/LevelSetList.php b/packages/Set/ValueObject/LevelSetList.php
index 865eb6f1b47..e0611fecdd2 100644
--- a/packages/Set/ValueObject/LevelSetList.php
+++ b/packages/Set/ValueObject/LevelSetList.php
@@ -11,6 +11,11 @@
*/
final class LevelSetList implements SetListInterface
{
+ /**
+ * @var string
+ */
+ public const UP_TO_PHP_83 = __DIR__ . '/../../../config/set/level/up-to-php83.php';
+
/**
* @var string
*/
diff --git a/packages/Set/ValueObject/SetList.php b/packages/Set/ValueObject/SetList.php
index 554fa3cefb4..c18643a87a1 100644
--- a/packages/Set/ValueObject/SetList.php
+++ b/packages/Set/ValueObject/SetList.php
@@ -106,6 +106,11 @@ final class SetList implements SetListInterface
*/
public const PHP_82 = __DIR__ . '/../../../config/set/php82.php';
+ /**
+ * @var string
+ */
+ public const PHP_83 = __DIR__ . '/../../../config/set/php83.php';
+
/**
* @var string
*/
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/AddOverrideAttributeToOverriddenMethodsRectorTest.php b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/AddOverrideAttributeToOverriddenMethodsRectorTest.php
new file mode 100644
index 00000000000..cb1bb9e537c
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/AddOverrideAttributeToOverriddenMethodsRectorTest.php
@@ -0,0 +1,28 @@
+doTestFile($filePath);
+ }
+
+ public static function provideData(): Iterator
+ {
+ return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
+ }
+
+ public function provideConfigFilePath(): string
+ {
+ return __DIR__ . '/config/configured_rule.php';
+ }
+}
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/apply_attribute_to_overridden_methods.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/apply_attribute_to_overridden_methods.php.inc
new file mode 100644
index 00000000000..40386f76494
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/apply_attribute_to_overridden_methods.php.inc
@@ -0,0 +1,30 @@
+
+-----
+
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/apply_attribute_to_overridden_methods_from_grandparent.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/apply_attribute_to_overridden_methods_from_grandparent.php.inc
new file mode 100644
index 00000000000..8a4506ef1d6
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/apply_attribute_to_overridden_methods_from_grandparent.php.inc
@@ -0,0 +1,30 @@
+
+-----
+
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_method_that_is_not_overridden.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_method_that_is_not_overridden.php.inc
new file mode 100644
index 00000000000..0600d2f861f
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_method_that_is_not_overridden.php.inc
@@ -0,0 +1,14 @@
+
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_on_construct.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_on_construct.php.inc
new file mode 100644
index 00000000000..82a16832531
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_on_construct.php.inc
@@ -0,0 +1,14 @@
+
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_on_non_inheriting_class.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_on_non_inheriting_class.php.inc
new file mode 100644
index 00000000000..6d0c8a31e42
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_on_non_inheriting_class.php.inc
@@ -0,0 +1,11 @@
+
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_override_attribute_exists.php.inc b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_override_attribute_exists.php.inc
new file mode 100644
index 00000000000..1bdabbd5aed
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Fixture/skip_override_attribute_exists.php.inc
@@ -0,0 +1,15 @@
+
diff --git a/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Source/ExampleChildClass.php b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Source/ExampleChildClass.php
new file mode 100644
index 00000000000..b827ec2bb02
--- /dev/null
+++ b/rules-tests/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector/Source/ExampleChildClass.php
@@ -0,0 +1,7 @@
+rule(AddOverrideAttributeToOverriddenMethodsRector::class);
+
+ $rectorConfig->phpVersion(PhpVersion::PHP_83);
+};
diff --git a/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php b/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php
new file mode 100644
index 00000000000..b8194e21fa1
--- /dev/null
+++ b/rules/Php83/Rector/ClassMethod/AddOverrideAttributeToOverriddenMethodsRector.php
@@ -0,0 +1,143 @@
+>
+ */
+ public function getNodeTypes(): array
+ {
+ return [Class_::class];
+ }
+
+ /**
+ * @param Class_ $node
+ */
+ public function refactor(Node $node): ?Node
+ {
+ // Detect if class extends a parent class
+ if ($this->shouldSkipClass($node)) {
+ return null;
+ }
+
+ // Fetch the parent class reflection
+ $parentClassReflection = $this->reflectionProvider->getClass((string) $node->extends);
+
+ $hasChanged = false;
+
+ foreach ($node->getMethods() as $method) {
+ if ($method->name->toString() === '__construct') {
+ continue;
+ }
+ // Private methods should be ignored
+ if ($parentClassReflection->hasNativeMethod($method->name->toString())) {
+ // ignore if it is a private method on the parent
+ $parentMethod = $parentClassReflection->getNativeMethod($method->name->toString());
+ if ($parentMethod->isPrivate()) {
+ continue;
+ }
+ // ignore if it already uses the attribute
+ if ($this->phpAttributeAnalyzer->hasPhpAttribute($method, 'Override')) {
+ continue;
+ }
+ $method->attrGroups[] = new AttributeGroup([new Attribute(new FullyQualified('Override'))]);
+ $hasChanged = true;
+ }
+ }
+
+ if (! $hasChanged) {
+ return null;
+ }
+
+ return $node;
+ }
+
+ public function provideMinPhpVersion(): int
+ {
+ return PhpVersionFeature::OVERRIDE_ATTRIBUTE;
+ }
+
+ private function shouldSkipClass(Class_ $class): bool
+ {
+ if ($this->classAnalyzer->isAnonymousClass($class)) {
+ return true;
+ }
+ if (! $class->extends instanceof FullyQualified) {
+ return true;
+ }
+
+ return ! $this->reflectionProvider->hasClass($class->extends->toString());
+ }
+}
diff --git a/src/ValueObject/PhpVersionFeature.php b/src/ValueObject/PhpVersionFeature.php
index c9048315e8b..bc41c89be98 100644
--- a/src/ValueObject/PhpVersionFeature.php
+++ b/src/ValueObject/PhpVersionFeature.php
@@ -643,4 +643,10 @@ final class PhpVersionFeature
* @var int
*/
public const SENSITIVE_PARAMETER_ATTRIBUTE = PhpVersion::PHP_82;
+
+ /**
+ * @see https://wiki.php.net/rfc/marking_overriden_methods
+ * @var int
+ */
+ public const OVERRIDE_ATTRIBUTE = PhpVersion::PHP_83;
}