From 53772ee6796d306e69b3cf01287413c13ab71a7d Mon Sep 17 00:00:00 2001 From: Matt Glaman Date: Fri, 27 Sep 2024 15:21:55 +0200 Subject: [PATCH] Add rule identifiers --- .../Classes/ClassExtendsInternalClassRule.php | 3 ++- src/Rules/Classes/PluginManagerInspectionRule.php | 14 +++++++++++--- .../Deprecations/AccessDeprecatedConstant.php | 5 ++++- ...nagerCreateInstanceContextConfigurationRule.php | 1 + .../Deprecations/ConfigEntityConfigExportRule.php | 5 ++++- .../Deprecations/DeprecatedHookImplementation.php | 2 +- .../Deprecations/GetDeprecatedServiceRule.php | 7 ++++++- .../PluginAnnotationContextDefinitionsRule.php | 5 ++++- .../StaticServiceDeprecatedServiceRule.php | 7 ++++++- ...SymfonyCmfRouteObjectInterfaceConstantsRule.php | 10 ++++++++-- ...SymfonyCmfRoutingInClassMethodSignatureRule.php | 6 ++++++ src/Rules/Drupal/AccessResultConditionRule.php | 1 + .../Drupal/Coder/DiscouragedFunctionsRule.php | 1 + .../DependencySerializationTraitPropertyRule.php | 2 ++ .../EntityQuery/EntityQueryHasAccessCheckRule.php | 1 + .../Drupal/GlobalDrupalDependencyInjectionRule.php | 1 + src/Rules/Drupal/LoadIncludes.php | 2 ++ src/Rules/Drupal/ModuleLoadInclude.php | 3 +++ .../PluginManagerSetsCacheBackendRule.php | 2 ++ src/Rules/Drupal/RenderCallbackRule.php | 11 +++++++++++ .../Drupal/RequestStackGetMainRequestRule.php | 1 + .../TestClassesProtectedPropertyModulesRule.php | 1 + .../Tests/BrowserTestBaseDefaultThemeRule.php | 1 + src/Rules/Drupal/Tests/TestClassSuffixNameRule.php | 1 + 24 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/Rules/Classes/ClassExtendsInternalClassRule.php b/src/Rules/Classes/ClassExtendsInternalClassRule.php index 2384b6f0..9a4e5399 100644 --- a/src/Rules/Classes/ClassExtendsInternalClassRule.php +++ b/src/Rules/Classes/ClassExtendsInternalClassRule.php @@ -76,6 +76,7 @@ private function buildError(?string $currentClassName, string $extendedClassName '%s extends @internal class %s.', $currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class', $extendedClassName - )); + )) + ->identifier('class.extendsInternalClass'); } } diff --git a/src/Rules/Classes/PluginManagerInspectionRule.php b/src/Rules/Classes/PluginManagerInspectionRule.php index 98871f9d..89f154ec 100644 --- a/src/Rules/Classes/PluginManagerInspectionRule.php +++ b/src/Rules/Classes/PluginManagerInspectionRule.php @@ -6,6 +6,8 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleError; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\Type\ObjectType; use function sprintf; @@ -67,7 +69,9 @@ public function processNode(Node $node, Scope $scope): array } if (!$hasAlterInfoSet) { - $errors[] = 'Plugin definitions cannot be altered.'; + $errors[] = RuleErrorBuilder::message('Plugin definitions cannot be altered.') + ->identifier('plugin.manager.alterInfoMissing') + ->build(); } return $errors; @@ -117,7 +121,9 @@ private function inspectYamlPluginManager(Node\Stmt\Class_ $class): array $constructor = $reflection->getConstructor(); if ($constructor->getDeclaringClass()->getName() !== $fqn) { - $errors[] = sprintf('%s must override __construct if using YAML plugins.', $fqn); + $errors[] = RuleErrorBuilder::message(sprintf('%s must override __construct if using YAML plugins.', $fqn)) + ->identifier('plugin.manager.yamlPluginConstructor') + ->build(); } else { foreach ($class->stmts as $stmt) { if ($stmt instanceof Node\Stmt\ClassMethod && $stmt->name->toString() === '__construct') { @@ -130,7 +136,9 @@ private function inspectYamlPluginManager(Node\Stmt\Class_ $class): array && ((string)$constructorStmt->class === 'parent') && $constructorStmt->name instanceof Node\Identifier && $constructorStmt->name->name === '__construct') { - $errors[] = sprintf('YAML plugin managers should not invoke its parent constructor.'); + $errors[] = RuleErrorBuilder::message('YAML plugin managers should not invoke its parent constructor.') + ->identifier('plugin.manager.yamlPluginConstructor') + ->build(); } } } diff --git a/src/Rules/Deprecations/AccessDeprecatedConstant.php b/src/Rules/Deprecations/AccessDeprecatedConstant.php index e7e0fd83..567ca3ab 100644 --- a/src/Rules/Deprecations/AccessDeprecatedConstant.php +++ b/src/Rules/Deprecations/AccessDeprecatedConstant.php @@ -8,6 +8,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; use function array_merge; use function explode; use function sprintf; @@ -124,7 +125,9 @@ public function processNode(Node $node, Scope $scope): array $constantName = $this->reflectionProvider->resolveConstantName($node->name, $scope); if (isset($deprecatedConstants[$constantName])) { return [ - sprintf('Call to deprecated constant %s: %s', $constantName, $deprecatedConstants[$constantName]) + RuleErrorBuilder::message(sprintf('Call to deprecated constant %s: %s', $constantName, $deprecatedConstants[$constantName])) + ->identifier('constant.deprecated') + ->build() ]; } return []; diff --git a/src/Rules/Deprecations/ConditionManagerCreateInstanceContextConfigurationRule.php b/src/Rules/Deprecations/ConditionManagerCreateInstanceContextConfigurationRule.php index d8a26cb9..351bcf3b 100644 --- a/src/Rules/Deprecations/ConditionManagerCreateInstanceContextConfigurationRule.php +++ b/src/Rules/Deprecations/ConditionManagerCreateInstanceContextConfigurationRule.php @@ -51,6 +51,7 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message('Passing context values to plugins via configuration is deprecated in drupal:9.1.0 and will be removed before drupal:10.0.0. Instead, call ::setContextValue() on the plugin itself. See https://www.drupal.org/node/3120980') ->line($node->getStartLine()) + ->identifier('drupal.deprecated.pluginConfigurationContextKey') ->build() ]; } diff --git a/src/Rules/Deprecations/ConfigEntityConfigExportRule.php b/src/Rules/Deprecations/ConfigEntityConfigExportRule.php index 1c4bcf5a..53c73bae 100644 --- a/src/Rules/Deprecations/ConfigEntityConfigExportRule.php +++ b/src/Rules/Deprecations/ConfigEntityConfigExportRule.php @@ -7,6 +7,7 @@ use PHPStan\PhpDoc\ResolvedPhpDocBlock; use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode; use PHPStan\Reflection\ClassReflection; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; use function preg_match; @@ -32,7 +33,9 @@ protected function doProcessNode(ClassReflection $reflection, Node\Stmt\Class_ $ } if ($hasMatch === 0) { return [ - 'Configuration entity must define a `config_export` key. See https://www.drupal.org/node/2481909', + RuleErrorBuilder::message('Configuration entity must define a `config_export` key. See https://www.drupal.org/node/2481909') + ->identifier('drupal.deprecated.configEntityConfigExportKey') + ->build(), ]; } return []; diff --git a/src/Rules/Deprecations/DeprecatedHookImplementation.php b/src/Rules/Deprecations/DeprecatedHookImplementation.php index a40425dc..bab32574 100644 --- a/src/Rules/Deprecations/DeprecatedHookImplementation.php +++ b/src/Rules/Deprecations/DeprecatedHookImplementation.php @@ -98,7 +98,7 @@ private function buildError(string $function_name, string $hook_name, ?string $d return [ RuleErrorBuilder::message( "Function $function_name implements $hook_name which is deprecated$deprecated_description", - )->build() + )->identifier('drupal.deprecated.hook')->build() ]; } } diff --git a/src/Rules/Deprecations/GetDeprecatedServiceRule.php b/src/Rules/Deprecations/GetDeprecatedServiceRule.php index 237563c6..ab3096ad 100644 --- a/src/Rules/Deprecations/GetDeprecatedServiceRule.php +++ b/src/Rules/Deprecations/GetDeprecatedServiceRule.php @@ -7,6 +7,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; /** * @implements Rule @@ -57,7 +58,11 @@ public function processNode(Node $node, Scope $scope): array $service = $this->serviceMap->getService($serviceName->value); if (($service instanceof DrupalServiceDefinition) && $service->isDeprecated()) { - return [$service->getDeprecatedDescription()]; + return [ + RuleErrorBuilder::message($service->getDeprecatedDescription()) + ->identifier('drupal.deprecated.service') + ->build() + ]; } return []; diff --git a/src/Rules/Deprecations/PluginAnnotationContextDefinitionsRule.php b/src/Rules/Deprecations/PluginAnnotationContextDefinitionsRule.php index 814ae8e8..6ca31896 100644 --- a/src/Rules/Deprecations/PluginAnnotationContextDefinitionsRule.php +++ b/src/Rules/Deprecations/PluginAnnotationContextDefinitionsRule.php @@ -5,6 +5,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Reflection\ClassReflection; +use PHPStan\Rules\RuleErrorBuilder; use PHPStan\ShouldNotHappenException; use function preg_match; @@ -30,7 +31,9 @@ protected function doProcessNode(ClassReflection $reflection, Node\Stmt\Class_ $ } if ($hasMatch === 1) { return [ - 'Providing context definitions via the "context" key is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.0. Use the "context_definitions" key instead.', + RuleErrorBuilder::message('Providing context definitions via the "context" key is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.0. Use the "context_definitions" key instead.') + ->identifier('drupal.deprecated.pluginAnnotationContextKey') + ->build(), ]; } return []; diff --git a/src/Rules/Deprecations/StaticServiceDeprecatedServiceRule.php b/src/Rules/Deprecations/StaticServiceDeprecatedServiceRule.php index 7637f8bc..777fcabb 100644 --- a/src/Rules/Deprecations/StaticServiceDeprecatedServiceRule.php +++ b/src/Rules/Deprecations/StaticServiceDeprecatedServiceRule.php @@ -7,6 +7,7 @@ use PhpParser\Node; use PHPStan\Analyser\Scope; use PHPStan\Rules\Rule; +use PHPStan\Rules\RuleErrorBuilder; /** * @implements Rule @@ -66,7 +67,11 @@ public function processNode(Node $node, Scope $scope): array $service = $this->serviceMap->getService($serviceName->value); if (($service instanceof DrupalServiceDefinition) && $service->isDeprecated()) { - return [$service->getDeprecatedDescription()]; + return [ + RuleErrorBuilder::message($service->getDeprecatedDescription()) + ->identifier('drupal.deprecated.service') + ->build() + ]; } return []; diff --git a/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php b/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php index 7236f836..d7f3f9a0 100644 --- a/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php +++ b/src/Rules/Deprecations/SymfonyCmfRouteObjectInterfaceConstantsRule.php @@ -60,14 +60,20 @@ public function processNode(Node $node, Scope $scope): array return [ RuleErrorBuilder::message( sprintf('The core dependency symfony-cmf/routing is deprecated and %s::%s is not supported.', $className, $constantName) - )->tip('Change record: https://www.drupal.org/node/3151009')->build(), + ) + ->tip('Change record: https://www.drupal.org/node/3151009') + ->identifier('drupal.deprecated.dependency') + ->build(), ]; } return [ RuleErrorBuilder::message( sprintf('%s::%s is deprecated and removed in Drupal 10. Use \Drupal\Core\Routing\RouteObjectInterface::%2$s instead.', $className, $constantName) - )->tip('Change record: https://www.drupal.org/node/3151009')->build(), + ) + ->tip('Change record: https://www.drupal.org/node/3151009') + ->identifier('drupal.deprecated.class') + ->build(), ]; } } diff --git a/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php b/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php index e96adbb6..251636e9 100644 --- a/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php +++ b/src/Rules/Deprecations/SymfonyCmfRoutingInClassMethodSignatureRule.php @@ -58,6 +58,7 @@ public function processNode(Node $node, Scope $scope): array foreach ($parameter->getType()->getReferencedClasses() as $referencedClass) { $referencedClassType = new ObjectType($referencedClass); if ($cmfRouteObjectInterfaceType->equals($referencedClassType)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( $errorMessage, @@ -68,6 +69,7 @@ public function processNode(Node $node, Scope $scope): array ) )->tip('Change record: https://www.drupal.org/node/3151009')->build(); } elseif ($cmfRouteProviderInterfaceType->equals($referencedClassType)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( $errorMessage, @@ -78,6 +80,7 @@ public function processNode(Node $node, Scope $scope): array ) )->tip('Change record: https://www.drupal.org/node/3151009')->build(); } elseif ($cmfLazyRouteCollectionType->equals($referencedClassType)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( $errorMessage, @@ -96,6 +99,7 @@ public function processNode(Node $node, Scope $scope): array foreach ($returnClasses as $returnClass) { $returnType = new ObjectType($returnClass); if ($cmfRouteObjectInterfaceType->equals($returnType)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( $errorMessage, @@ -106,6 +110,7 @@ public function processNode(Node $node, Scope $scope): array ) )->tip('Change record: https://www.drupal.org/node/3151009')->build(); } elseif ($cmfRouteProviderInterfaceType->equals($returnType)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( $errorMessage, @@ -116,6 +121,7 @@ public function processNode(Node $node, Scope $scope): array ) )->tip('Change record: https://www.drupal.org/node/3151009')->build(); } elseif ($cmfLazyRouteCollectionType->equals($returnType)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( $errorMessage, diff --git a/src/Rules/Drupal/AccessResultConditionRule.php b/src/Rules/Drupal/AccessResultConditionRule.php index 25c894b8..54c740e5 100644 --- a/src/Rules/Drupal/AccessResultConditionRule.php +++ b/src/Rules/Drupal/AccessResultConditionRule.php @@ -65,6 +65,7 @@ public function processNode(Node $node, Scope $scope): array $rightType = $this->treatPhpDocTypesAsCertain ? $scope->getType($condition->right) : $scope->getNativeType($condition->right); return [ + // @todo identifier RuleErrorBuilder::message(sprintf( 'Strict comparison using %s between %s and %s will always evaluate to %s.', $condition->getOperatorSigil(), diff --git a/src/Rules/Drupal/Coder/DiscouragedFunctionsRule.php b/src/Rules/Drupal/Coder/DiscouragedFunctionsRule.php index f6e9c119..9bd7f950 100644 --- a/src/Rules/Drupal/Coder/DiscouragedFunctionsRule.php +++ b/src/Rules/Drupal/Coder/DiscouragedFunctionsRule.php @@ -56,6 +56,7 @@ public function processNode(Node $node, Scope $scope): array ]; if (in_array($name, $discouragedFunctions, true)) { + // @todo identifier return [sprintf('Calls to function %s should not exist.', $name)]; } return []; diff --git a/src/Rules/Drupal/DependencySerializationTraitPropertyRule.php b/src/Rules/Drupal/DependencySerializationTraitPropertyRule.php index 5d35c955..767fa45c 100644 --- a/src/Rules/Drupal/DependencySerializationTraitPropertyRule.php +++ b/src/Rules/Drupal/DependencySerializationTraitPropertyRule.php @@ -30,6 +30,7 @@ public function processNode(Node $node, Scope $scope): array $errors = []; if ($node->isPrivate()) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( '%s does not support private properties.', @@ -38,6 +39,7 @@ public function processNode(Node $node, Scope $scope): array )->tip('See https://www.drupal.org/node/3110266')->build(); } if ($node->isReadOnly()) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( 'Read-only properties are incompatible with %s.', diff --git a/src/Rules/Drupal/EntityQuery/EntityQueryHasAccessCheckRule.php b/src/Rules/Drupal/EntityQuery/EntityQueryHasAccessCheckRule.php index 46915b4e..795b976e 100644 --- a/src/Rules/Drupal/EntityQuery/EntityQueryHasAccessCheckRule.php +++ b/src/Rules/Drupal/EntityQuery/EntityQueryHasAccessCheckRule.php @@ -44,6 +44,7 @@ public function processNode(Node $node, Scope $scope): array } return [ + // @todo identifier RuleErrorBuilder::message( 'Relying on entity queries to check access by default is deprecated in drupal:9.2.0 and an error will be thrown from drupal:10.0.0. Call \Drupal\Core\Entity\Query\QueryInterface::accessCheck() with TRUE or FALSE to specify whether access should be checked.' )->tip('See https://www.drupal.org/node/3201242')->build(), diff --git a/src/Rules/Drupal/GlobalDrupalDependencyInjectionRule.php b/src/Rules/Drupal/GlobalDrupalDependencyInjectionRule.php index 068197cd..226ae2c0 100644 --- a/src/Rules/Drupal/GlobalDrupalDependencyInjectionRule.php +++ b/src/Rules/Drupal/GlobalDrupalDependencyInjectionRule.php @@ -71,6 +71,7 @@ public function processNode(Node $node, Scope $scope): array return []; } + // @todo identifier return [ '\Drupal calls should be avoided in classes, use dependency injection instead' ]; diff --git a/src/Rules/Drupal/LoadIncludes.php b/src/Rules/Drupal/LoadIncludes.php index 2c2f4a6e..f63b9eb3 100644 --- a/src/Rules/Drupal/LoadIncludes.php +++ b/src/Rules/Drupal/LoadIncludes.php @@ -53,6 +53,7 @@ public function processNode(Node $node, Scope $scope): array $module = $this->extensionMap->getModule($moduleName); if ($module === null) { return [ + // @todo identifier RuleErrorBuilder::message(sprintf( 'File %s could not be loaded from %s::loadInclude because %s module is not found.', $filename, @@ -80,6 +81,7 @@ public function processNode(Node $node, Scope $scope): array ]; } catch (Throwable $e) { return [ + // @todo identifier RuleErrorBuilder::message(sprintf( 'A file could not be loaded from %s::loadInclude', ModuleHandlerInterface::class diff --git a/src/Rules/Drupal/ModuleLoadInclude.php b/src/Rules/Drupal/ModuleLoadInclude.php index 2170bff1..43c453e9 100644 --- a/src/Rules/Drupal/ModuleLoadInclude.php +++ b/src/Rules/Drupal/ModuleLoadInclude.php @@ -47,6 +47,7 @@ public function processNode(Node $node, Scope $scope): array $module = $this->extensionMap->getModule($moduleName); if ($module === null) { return [ + // @todo identifier RuleErrorBuilder::message(sprintf( 'File %s could not be loaded from module_load_include because %s module is not found.', $filename, @@ -62,6 +63,7 @@ public function processNode(Node $node, Scope $scope): array return []; } return [ + // @todo identifier RuleErrorBuilder::message(sprintf( 'File %s could not be loaded from module_load_include.', $module->getPath() . '/' . $filename @@ -71,6 +73,7 @@ public function processNode(Node $node, Scope $scope): array ]; } catch (Throwable $e) { return [ + // @todo identifier RuleErrorBuilder::message('A file could not be loaded from module_load_include') ->line($node->getStartLine()) ->build() diff --git a/src/Rules/Drupal/PluginManager/PluginManagerSetsCacheBackendRule.php b/src/Rules/Drupal/PluginManager/PluginManagerSetsCacheBackendRule.php index b053e105..da322f88 100644 --- a/src/Rules/Drupal/PluginManager/PluginManagerSetsCacheBackendRule.php +++ b/src/Rules/Drupal/PluginManager/PluginManagerSetsCacheBackendRule.php @@ -88,9 +88,11 @@ public function processNode(Node $node, Scope $scope): array $errors = []; if (!$hasCacheBackendSet) { + // @todo identifier $errors[] = 'Missing cache backend declaration for performance.'; } foreach ($misnamedCacheTagWarnings as $cacheTagWarning) { + // @todo identifier $errors[] = sprintf('%s cache tag might be unclear and does not contain the cache key in it.', $cacheTagWarning); } diff --git a/src/Rules/Drupal/RenderCallbackRule.php b/src/Rules/Drupal/RenderCallbackRule.php index 413d943e..302c2ce6 100644 --- a/src/Rules/Drupal/RenderCallbackRule.php +++ b/src/Rules/Drupal/RenderCallbackRule.php @@ -105,6 +105,7 @@ public function processNode(Node $node, Scope $scope): array if (!$value instanceof Node\Expr\Array_) { return [ + // @todo identifier RuleErrorBuilder::message(sprintf('The "%s" expects a callable array with arguments.', $keyChecked)) ->line($node->getStartLine())->build() ]; @@ -118,6 +119,7 @@ public function processNode(Node $node, Scope $scope): array if (!$value instanceof Node\Expr\Array_) { return [ + // @todo identifier RuleErrorBuilder::message(sprintf('The "%s" render array value expects an array of callbacks.', $keyChecked)) ->line($node->getStartLine())->build() ]; @@ -150,12 +152,14 @@ private function doProcessNode(Node\Expr $node, Scope $scope, string $keyChecked foreach ($type->getConstantStrings() as $constantStringType) { if (!$constantStringType->isCallable()->yes()) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s callback %s at key '%s' is not callable.", $keyChecked, $constantStringType->describe(VerbosityLevel::value()), $pos) )->line($errorLine)->build(); } elseif ($this->reflectionProvider->hasFunction(new Name($constantStringType->getValue()), null)) { // We can determine if the callback is callable through the type system. However, we cannot determine // if it is just a function or a static class call (MyClass::staticFunc). + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s callback %s at key '%s' is not trusted.", $keyChecked, $constantStringType->describe(VerbosityLevel::value()), $pos) )->line($errorLine) @@ -165,10 +169,12 @@ private function doProcessNode(Node\Expr $node, Scope $scope, string $keyChecked // @see \PHPStan\Type\Constant\ConstantStringType::isCallable preg_match('#^([a-zA-Z_\\x7f-\\xff\\\\][a-zA-Z0-9_\\x7f-\\xff\\\\]*)::([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)\\z#', $constantStringType->getValue(), $matches); if (count($matches) === 0) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s callback %s at key '%s' is not callable.", $keyChecked, $constantStringType->describe(VerbosityLevel::value()), $pos) )->line($errorLine)->build(); } elseif (!$trustedCallbackType->isSuperTypeOf(new ObjectType($matches[1]))->yes()) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s callback class %s at key '%s' does not implement Drupal\Core\Security\TrustedCallbackInterface.", $keyChecked, $constantStringType->describe(VerbosityLevel::value()), $pos) )->line($errorLine)->tip('Change record: https://www.drupal.org/node/2966725.')->build(); @@ -192,6 +198,7 @@ private function doProcessNode(Node\Expr $node, Scope $scope, string $keyChecked break; } } + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s callback %s at key '%s' is not callable.", $keyChecked, $constantArrayType->describe(VerbosityLevel::value()), $pos) )->line($errorLine)->build(); @@ -219,6 +226,7 @@ function (ClassReflection $reflection) use ($typeAndMethodName) { $isTrustedCallbackInterfaceType = $trustedCallbackType->isSuperTypeOf($typeAndMethodName->getType())->yes(); if (!$isTrustedCallbackInterfaceType && !$isTrustedCallbackAttribute->yes()) { if (class_exists(TrustedCallback::class)) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( "%s callback method '%s' at key '%s' does not implement attribute \Drupal\Core\Security\Attribute\TrustedCallback.", @@ -228,6 +236,7 @@ function (ClassReflection $reflection) use ($typeAndMethodName) { ) )->line($errorLine)->tip('Change record: https://www.drupal.org/node/3349470')->build(); } else { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf( "%s callback class '%s' at key '%s' does not implement Drupal\Core\Security\TrustedCallbackInterface.", @@ -246,6 +255,7 @@ function (ClassReflection $reflection) use ($typeAndMethodName) { $classType = new ObjectType($classReflection->getName()); $formType = new ObjectType('\Drupal\Core\Form\FormInterface'); if ($formType->isSuperTypeOf($classType)->yes()) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s may not contain a closure at key '%s' as forms may be serialized and serialization of closures is not allowed.", $keyChecked, $pos) )->line($errorLine)->build(); @@ -253,6 +263,7 @@ function (ClassReflection $reflection) use ($typeAndMethodName) { } if (count($errors) === 0 && ($checkIsCallable && !$type->isCallable()->yes())) { + // @todo identifier $errors[] = RuleErrorBuilder::message( sprintf("%s value '%s' at key '%s' is invalid.", $keyChecked, $type->describe(VerbosityLevel::value()), $pos) )->line($errorLine)->build(); diff --git a/src/Rules/Drupal/RequestStackGetMainRequestRule.php b/src/Rules/Drupal/RequestStackGetMainRequestRule.php index b4f78665..d3c53c57 100644 --- a/src/Rules/Drupal/RequestStackGetMainRequestRule.php +++ b/src/Rules/Drupal/RequestStackGetMainRequestRule.php @@ -49,6 +49,7 @@ public function processNode(Node $node, Scope $scope): array SymfonyRequestStack::class, 'Drupal\Core\Http\RequestStack' ); + // @todo identifier return [ RuleErrorBuilder::message($message) ->tip('Change record: https://www.drupal.org/node/3253744') diff --git a/src/Rules/Drupal/TestClassesProtectedPropertyModulesRule.php b/src/Rules/Drupal/TestClassesProtectedPropertyModulesRule.php index 8194b327..8fa9e0f7 100644 --- a/src/Rules/Drupal/TestClassesProtectedPropertyModulesRule.php +++ b/src/Rules/Drupal/TestClassesProtectedPropertyModulesRule.php @@ -44,6 +44,7 @@ public function processNode(Node $node, Scope $scope): array if ($node->isPublic()) { return [ + // @todo identifier RuleErrorBuilder::message( sprintf('Property %s::$modules property must be protected.', $scopeClassReflection->getDisplayName()) )->tip('Change record: https://www.drupal.org/node/2909426')->build(), diff --git a/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php b/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php index 29648c2d..3832d9b5 100644 --- a/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php +++ b/src/Rules/Drupal/Tests/BrowserTestBaseDefaultThemeRule.php @@ -103,6 +103,7 @@ public function processNode(Node $node, Scope $scope): array if ($defaultTheme === null || $defaultTheme === '') { return [ + // @todo identifier RuleErrorBuilder::message('Drupal\Tests\BrowserTestBase::$defaultTheme is required. See https://www.drupal.org/node/3083055, which includes recommendations on which theme to use.') ->line($node->getStartLine())->build(), ]; diff --git a/src/Rules/Drupal/Tests/TestClassSuffixNameRule.php b/src/Rules/Drupal/Tests/TestClassSuffixNameRule.php index 6f8b83ea..5fe81ec0 100644 --- a/src/Rules/Drupal/Tests/TestClassSuffixNameRule.php +++ b/src/Rules/Drupal/Tests/TestClassSuffixNameRule.php @@ -62,6 +62,7 @@ public function processNode(Node $node, Scope $scope): array ) ) ->line($node->getStartLine()) + ->identifier('drupal.testSuffix') ->tip('See https://www.drupal.org/docs/develop/standards/php/object-oriented-code#naming') ->build() ];