diff --git a/lib/classes/deprecation.php b/lib/classes/deprecation.php index 39aae1e5214..e11b12058ac 100644 --- a/lib/classes/deprecation.php +++ b/lib/classes/deprecation.php @@ -45,7 +45,7 @@ class deprecation { return self::from(explode('::', $reference)); } - if (class_exists($reference)) { + if (class_exists($reference) || interface_exists($reference) || trait_exists($reference)) { // The reference looks to be a class name. return self::from([$reference]); } @@ -75,9 +75,11 @@ class deprecation { return self::from_reflected_object($rc, $reference[1] ?? null); } - if (is_string($reference[0]) && class_exists($reference[0])) { - $rc = new \ReflectionClass($reference[0]); - return self::from_reflected_object($rc, $reference[1] ?? null); + if (is_string($reference[0])) { + if (class_exists($reference[0]) || interface_exists($reference[0]) || trait_exists($reference[0])) { + $rc = new \ReflectionClass($reference[0]); + return self::from_reflected_object($rc, $reference[1] ?? null); + } } // The reference is an array, but it's not an object or a class that currently exists. @@ -152,6 +154,20 @@ class deprecation { return $classattribute; } + // Check for any deprecated interfaces. + foreach ($rc->getInterfaces() as $interface) { + if ($attribute = self::get_attribute($interface, $interface->name)) { + return $attribute; + } + } + + // And any deprecated traits. + foreach ($rc->getTraits() as $trait) { + if ($attribute = self::get_attribute($trait, $trait->name)) { + return $attribute; + } + } + if ($rc->hasConstant($name)) { // This class has a constant with the specified name. // Note: This also applies to enums. diff --git a/lib/tests/deprecation_test.php b/lib/tests/deprecation_test.php index f0b50242680..bebad9ce3fc 100644 --- a/lib/tests/deprecation_test.php +++ b/lib/tests/deprecation_test.php @@ -226,16 +226,36 @@ class deprecation_test extends \advanced_testcase { return [ // Classes. [\core\fixtures\deprecated_class::class, true], + [\core\fixtures\deprecated_interface::class, true], + [\core\fixtures\deprecated_trait::class, true], [[\core\fixtures\deprecated_class::class], true], + [[\core\fixtures\deprecated_interface::class], true], + [[\core\fixtures\deprecated_trait::class], true], + + [\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class, false], + [[\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class], false], + [\core\fixtures\not_deprecated_class::class, false], + [\core\fixtures\not_deprecated_interface::class, false], + [\core\fixtures\not_deprecated_trait::class, false], [[\core\fixtures\not_deprecated_class::class], false], + [[\core\fixtures\not_deprecated_interface::class], false], + [[\core\fixtures\not_deprecated_trait::class], false], // Class properties in a deprecated class. [\core\fixtures\deprecated_class::class . '::deprecatedproperty', true], [[\core\fixtures\deprecated_class::class, 'deprecatedproperty'], true], + [\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class . '::deprecatedproperty', true], + [[\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class, 'deprecatedproperty'], true], + [\core\fixtures\not_deprecated_class_using_not_deprecated_trait_features::class . '::deprecatedproperty', true], + [[\core\fixtures\not_deprecated_class_using_not_deprecated_trait_features::class, 'deprecatedproperty'], true], [\core\fixtures\deprecated_class::class . '::notdeprecatedproperty', true], [[\core\fixtures\deprecated_class::class, 'notdeprecatedproperty'], true], + [\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class . '::notdeprecatedproperty', true], + [[\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class, 'notdeprecatedproperty'], true], + [\core\fixtures\not_deprecated_class_using_not_deprecated_trait_features::class . '::notdeprecatedproperty', false], + [[\core\fixtures\not_deprecated_class_using_not_deprecated_trait_features::class, 'notdeprecatedproperty'], false], // Class constants in a deprecated class. [\core\fixtures\deprecated_class::class . '::DEPRECATED_CONST', true], @@ -248,9 +268,19 @@ class deprecation_test extends \advanced_testcase { [\core\fixtures\deprecated_class::class . '::deprecated_method', true], [[\core\fixtures\deprecated_class::class, 'deprecated_method'], true], + [\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class . '::deprecated_method', true], + [[\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class, 'deprecated_method'], true], + [\core\fixtures\not_deprecated_class_using_not_deprecated_trait_features::class . '::deprecated_method', true], + [[\core\fixtures\not_deprecated_class_using_not_deprecated_trait_features::class, 'deprecated_method'], true], + [\core\fixtures\deprecated_class::class . '::not_deprecated_method', true], [[\core\fixtures\deprecated_class::class, 'not_deprecated_method'], true], + [\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class . '::not_deprecated_method', true], + [[\core\fixtures\not_deprecated_class_using_deprecated_trait_features::class, 'not_deprecated_method'], true], + [\core\fixtures\not_deprecated_class_implementing_deprecated_interface::class . '::not_deprecated_method', true], + [[\core\fixtures\not_deprecated_class_implementing_deprecated_interface::class, 'not_deprecated_method'], true], + // Class properties in a not-deprecated class. [\core\fixtures\not_deprecated_class::class . '::deprecatedproperty', true], [[\core\fixtures\not_deprecated_class::class, 'deprecatedproperty'], true], @@ -265,6 +295,12 @@ class deprecation_test extends \advanced_testcase { [\core\fixtures\not_deprecated_class::class . '::NOT_DEPRECATED_CONST', false], [[\core\fixtures\not_deprecated_class::class, 'NOT_DEPRECATED_CONST'], false], + [\core\fixtures\not_deprecated_interface::class . '::DEPRECATED_CONST', true], + [[\core\fixtures\not_deprecated_interface::class, 'DEPRECATED_CONST'], true], + + [\core\fixtures\not_deprecated_interface::class . '::NOT_DEPRECATED_CONST', false], + [[\core\fixtures\not_deprecated_interface::class, 'NOT_DEPRECATED_CONST'], false], + // Class methods in a not-deprecated class. [\core\fixtures\not_deprecated_class::class . '::deprecated_method', true], [[\core\fixtures\not_deprecated_class::class, 'deprecated_method'], true], diff --git a/lib/tests/fixtures/deprecated_fixtures.php b/lib/tests/fixtures/deprecated_fixtures.php index 699862b3aa7..3956671127d 100644 --- a/lib/tests/fixtures/deprecated_fixtures.php +++ b/lib/tests/fixtures/deprecated_fixtures.php @@ -71,3 +71,66 @@ function not_deprecated_function() { #[deprecated('not_deprecated_class::not_deprecated_method()')] function deprecated_function() { } + +interface not_deprecated_interface { + const NOT_DEPRECATED_CONST = 'Not deprecated const'; + + #[deprecated('self::NOT_DEPRECATED_CONST')] + const DEPRECATED_CONST = 'Deprecated const'; + + // Note: It does not make sense to deprecate methods in an _interface_ as the interface itself should be deprecated. +} + +#[deprecated('not_deprecated_interface')] +interface deprecated_interface { + const DEPRECATED_CONST = 'Deprecated const'; + + public function not_deprecated_method(); +} + +trait not_deprecated_trait { + protected string $notdeprecatedproperty = 'Not deprecated property'; + + #[deprecated('$this->notdeprecatedproperty')] + protected string $deprecatedproperty = 'Deprecated property'; + + public function not_deprecated_method() { + } + + #[deprecated('$this->not_deprecated_method()')] + public function deprecated_method() { + } +} + +#[deprecated(not_deprecated_trait::class)] +trait deprecated_trait { + protected string $notdeprecatedproperty = 'Not deprecated property'; + + #[deprecated('$this->notdeprecatedproperty')] + protected string $deprecatedproperty = 'Deprecated property'; + + public function not_deprecated_method() { + } + + #[deprecated(replacement: null, mdl: 'MDL-80677')] + public function deprecated_method() { + } +} + +class not_deprecated_class_using_deprecated_trait_features { + use deprecated_trait; +} + +class not_deprecated_class_implementing_deprecated_interface implements deprecated_interface { + public function not_deprecated_method() { + } +} + +class not_deprecated_class_using_not_deprecated_trait_features { + use not_deprecated_trait; +} + +class not_deprecated_class_implementing_not_deprecated_interface implements not_deprecated_interface { + public function not_deprecated_method() { + } +}