clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
<?php declare(strict_types = 1);
namespace PHPStan\DependencyInjection;
use PHPStan\Rules\Deprecations\DeprecatedScopeHelper;
final class LazyDeprecatedScopeResolverProvider
{
public const EXTENSION_TAG = 'phpstan.deprecations.deprecatedScopeResolver';
/** @var Container */
private $container;
/** @var DeprecatedScopeHelper */
private $scopeHelper;
public function __construct(Container $container)
{
$this->container = $container;
}
public function get(): DeprecatedScopeHelper
{
if ($this->scopeHelper === null) {
$this->scopeHelper = new DeprecatedScopeHelper(
$this->container->getServicesByTag(self::EXTENSION_TAG)
);
}
return $this->scopeHelper;
}
}

View File

@@ -0,0 +1,92 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Identifier;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\MissingPropertyFromReflectionException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
use function strtolower;
/**
* @implements Rule<PropertyFetch>
*/
class AccessDeprecatedPropertyRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return PropertyFetch::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!$node->name instanceof Identifier) {
return [];
}
$propertyName = $node->name->name;
$propertyAccessedOnType = $scope->getType($node->var);
$referencedClasses = $propertyAccessedOnType->getObjectClassNames();
foreach ($referencedClasses as $referencedClass) {
try {
$classReflection = $this->reflectionProvider->getClass($referencedClass);
$propertyReflection = $classReflection->getProperty($propertyName, $scope);
if ($propertyReflection->isDeprecated()->yes()) {
$description = $propertyReflection->getDeprecatedDescription();
if ($description === null) {
return [
RuleErrorBuilder::message(sprintf(
'Access to deprecated property $%s of %s %s.',
$propertyName,
strtolower($propertyReflection->getDeclaringClass()->getClassTypeDescription()),
$propertyReflection->getDeclaringClass()->getName()
))->identifier('property.deprecated')->build(),
];
}
return [
RuleErrorBuilder::message(sprintf(
"Access to deprecated property $%s of %s %s:\n%s",
$propertyName,
strtolower($propertyReflection->getDeclaringClass()->getClassTypeDescription()),
$propertyReflection->getDeclaringClass()->getName(),
$description
))->identifier('property.deprecated')->build(),
];
}
} catch (ClassNotFoundException $e) {
// Other rules will notify if the class is not found
} catch (MissingPropertyFromReflectionException $e) {
// Other rules will notify if the property is not found
}
}
return [];
}
}

View File

@@ -0,0 +1,118 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\MissingPropertyFromReflectionException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use function sprintf;
use function strtolower;
/**
* @implements Rule<StaticPropertyFetch>
*/
class AccessDeprecatedStaticPropertyRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var RuleLevelHelper */
private $ruleLevelHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return StaticPropertyFetch::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!$node->name instanceof Identifier) {
return [];
}
$propertyName = $node->name->name;
$referencedClasses = [];
if ($node->class instanceof Name) {
$referencedClasses[] = $scope->resolveName($node->class);
} else {
$classTypeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->class,
'', // We don't care about the error message
static function (Type $type) use ($propertyName): bool {
return $type->canAccessProperties()->yes() && $type->hasProperty($propertyName)->yes();
}
);
if ($classTypeResult->getType() instanceof ErrorType) {
return [];
}
$referencedClasses = $classTypeResult->getReferencedClasses();
}
foreach ($referencedClasses as $referencedClass) {
try {
$class = $this->reflectionProvider->getClass($referencedClass);
$property = $class->getProperty($propertyName, $scope);
} catch (ClassNotFoundException $e) {
continue;
} catch (MissingPropertyFromReflectionException $e) {
continue;
}
if ($property->isDeprecated()->yes()) {
$description = $property->getDeprecatedDescription();
if ($description === null) {
return [
RuleErrorBuilder::message(sprintf(
'Access to deprecated static property $%s of %s %s.',
$propertyName,
strtolower($property->getDeclaringClass()->getClassTypeDescription()),
$property->getDeclaringClass()->getName()
))->identifier('staticProperty.deprecated')->build(),
];
}
return [
RuleErrorBuilder::message(sprintf(
"Access to deprecated static property $%s of %s %s:\n%s",
$propertyName,
strtolower($property->getDeclaringClass()->getClassTypeDescription()),
$property->getDeclaringClass()->getName(),
$description
))->identifier('staticProperty.deprecated')->build(),
];
}
}
return [];
}
}

View File

@@ -0,0 +1,78 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\FunctionNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
/**
* @implements Rule<FuncCall>
*/
class CallToDeprecatedFunctionRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return FuncCall::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!($node->name instanceof Name)) {
return [];
}
try {
$function = $this->reflectionProvider->getFunction($node->name, $scope);
} catch (FunctionNotFoundException $e) {
// Other rules will notify if the function is not found
return [];
}
if ($function->isDeprecated()->yes()) {
$description = $function->getDeprecatedDescription();
if ($description === null) {
return [
RuleErrorBuilder::message(sprintf(
'Call to deprecated function %s().',
$function->getName()
))->identifier('function.deprecated')->build(),
];
}
return [
RuleErrorBuilder::message(sprintf(
"Call to deprecated function %s():\n%s",
$function->getName(),
$description
))->identifier('function.deprecated')->build(),
];
}
return [];
}
}

View File

@@ -0,0 +1,94 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Identifier;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\MissingMethodFromReflectionException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
use function strtolower;
/**
* @implements Rule<MethodCall>
*/
class CallToDeprecatedMethodRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return MethodCall::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!$node->name instanceof Identifier) {
return [];
}
$methodName = $node->name->name;
$methodCalledOnType = $scope->getType($node->var);
$referencedClasses = $methodCalledOnType->getObjectClassNames();
foreach ($referencedClasses as $referencedClass) {
try {
$classReflection = $this->reflectionProvider->getClass($referencedClass);
$methodReflection = $classReflection->getMethod($methodName, $scope);
if (!$methodReflection->isDeprecated()->yes()) {
continue;
}
$description = $methodReflection->getDeprecatedDescription();
if ($description === null) {
return [
RuleErrorBuilder::message(sprintf(
'Call to deprecated method %s() of %s %s.',
$methodReflection->getName(),
strtolower($methodReflection->getDeclaringClass()->getClassTypeDescription()),
$methodReflection->getDeclaringClass()->getName()
))->identifier('method.deprecated')->build(),
];
}
return [
RuleErrorBuilder::message(sprintf(
"Call to deprecated method %s() of %s %s:\n%s",
$methodReflection->getName(),
strtolower($methodReflection->getDeclaringClass()->getClassTypeDescription()),
$methodReflection->getDeclaringClass()->getName(),
$description
))->identifier('method.deprecated')->build(),
];
} catch (ClassNotFoundException $e) {
// Other rules will notify if the class is not found
} catch (MissingMethodFromReflectionException $e) {
// Other rules will notify if the the method is not found
}
}
return [];
}
}

View File

@@ -0,0 +1,138 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\MissingMethodFromReflectionException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use function sprintf;
use function strtolower;
/**
* @implements Rule<StaticCall>
*/
class CallToDeprecatedStaticMethodRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var RuleLevelHelper */
private $ruleLevelHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return StaticCall::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!$node->name instanceof Identifier) {
return [];
}
$methodName = $node->name->name;
$referencedClasses = [];
if ($node->class instanceof Name) {
$referencedClasses[] = $scope->resolveName($node->class);
} else {
$classTypeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->class,
'', // We don't care about the error message
static function (Type $type) use ($methodName): bool {
return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes();
}
);
if ($classTypeResult->getType() instanceof ErrorType) {
return [];
}
$referencedClasses = $classTypeResult->getReferencedClasses();
}
$errors = [];
foreach ($referencedClasses as $referencedClass) {
try {
$class = $this->reflectionProvider->getClass($referencedClass);
$methodReflection = $class->getMethod($methodName, $scope);
} catch (ClassNotFoundException $e) {
continue;
} catch (MissingMethodFromReflectionException $e) {
continue;
}
if ($class->isDeprecated()) {
$classDescription = $class->getDeprecatedDescription();
if ($classDescription === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Call to method %s() of deprecated %s %s.',
$methodReflection->getName(),
strtolower($methodReflection->getDeclaringClass()->getClassTypeDescription()),
$methodReflection->getDeclaringClass()->getName()
))->identifier(sprintf('staticMethod.deprecated%s', $methodReflection->getDeclaringClass()->getClassTypeDescription()))->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Call to method %s() of deprecated %s %s:\n%s",
$methodReflection->getName(),
strtolower($methodReflection->getDeclaringClass()->getClassTypeDescription()),
$methodReflection->getDeclaringClass()->getName(),
$classDescription
))->identifier(sprintf('staticMethod.deprecated%s', $methodReflection->getDeclaringClass()->getClassTypeDescription()))->build();
}
}
if (!$methodReflection->isDeprecated()->yes()) {
continue;
}
$description = $methodReflection->getDeprecatedDescription();
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Call to deprecated method %s() of %s %s.',
$methodReflection->getName(),
strtolower($methodReflection->getDeclaringClass()->getClassTypeDescription()),
$methodReflection->getDeclaringClass()->getName()
))->identifier('staticMethod.deprecated')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Call to deprecated method %s() of %s %s:\n%s",
$methodReflection->getName(),
strtolower($methodReflection->getDeclaringClass()->getClassTypeDescription()),
$methodReflection->getDeclaringClass()->getName(),
$description
))->identifier('staticMethod.deprecated')->build();
}
}
return $errors;
}
}

View File

@@ -0,0 +1,30 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PHPStan\Analyser\Scope;
final class DefaultDeprecatedScopeResolver implements DeprecatedScopeResolver
{
public function isScopeDeprecated(Scope $scope): bool
{
$class = $scope->getClassReflection();
if ($class !== null && $class->isDeprecated()) {
return true;
}
$trait = $scope->getTraitReflection();
if ($trait !== null && $trait->isDeprecated()) {
return true;
}
$function = $scope->getFunction();
if ($function !== null && $function->isDeprecated()->yes()) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,55 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use function sprintf;
class DeprecatedClassHelper
{
/** @var ReflectionProvider */
private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
}
public function getClassDeprecationDescription(ClassReflection $class): string
{
$description = $class->getDeprecatedDescription();
if ($description === null) {
return '.';
}
return sprintf(":\n%s", $description);
}
/**
* @param string[] $referencedClasses
* @return ClassReflection[]
*/
public function filterDeprecatedClasses(array $referencedClasses): array
{
$deprecatedClasses = [];
foreach ($referencedClasses as $referencedClass) {
try {
$class = $this->reflectionProvider->getClass($referencedClass);
} catch (ClassNotFoundException $e) {
continue;
}
if (!$class->isDeprecated()) {
continue;
}
$deprecatedClasses[] = $class;
}
return $deprecatedClasses;
}
}

View File

@@ -0,0 +1,32 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PHPStan\Analyser\Scope;
class DeprecatedScopeHelper
{
/** @var DeprecatedScopeResolver[] */
private $resolvers;
/**
* @param DeprecatedScopeResolver[] $checkers
*/
public function __construct(array $checkers)
{
$this->resolvers = $checkers;
}
public function isScopeDeprecated(Scope $scope): bool
{
foreach ($this->resolvers as $checker) {
if ($checker->isScopeDeprecated($scope)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,27 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PHPStan\Analyser\Scope;
/**
* This is the interface for custom deprecated scope resolvers.
*
* To register it in the configuration file use the `phpstan.deprecations.deprecatedScopeResolver` service tag:
*
* ```
* services:
* -
* class: App\PHPStan\MyExtension
* tags:
* - phpstan.deprecations.deprecatedScopeResolver
* ```
*
* @api
*/
interface DeprecatedScopeResolver
{
public function isScopeDeprecated(Scope $scope): bool;
}

View File

@@ -0,0 +1,144 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use PHPStan\Type\Type;
use function sprintf;
use function strtolower;
/**
* @implements Rule<ClassConstFetch>
*/
class FetchingClassConstOfDeprecatedClassRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var RuleLevelHelper */
private $ruleLevelHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return ClassConstFetch::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!$node->name instanceof Identifier) {
return [];
}
$constantName = $node->name->name;
$referencedClasses = [];
if ($node->class instanceof Name) {
$referencedClasses[] = $scope->resolveName($node->class);
} else {
$classTypeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->class,
'', // We don't care about the error message
static function (Type $type) use ($constantName): bool {
return $type->canAccessConstants()->yes() && $type->hasConstant($constantName)->yes();
}
);
if ($classTypeResult->getType() instanceof ErrorType) {
return [];
}
$referencedClasses = $classTypeResult->getReferencedClasses();
}
$errors = [];
foreach ($referencedClasses as $referencedClass) {
try {
$class = $this->reflectionProvider->getClass($referencedClass);
} catch (ClassNotFoundException $e) {
continue;
}
if ($class->isDeprecated()) {
$classDescription = $class->getDeprecatedDescription();
if ($classDescription === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Fetching class constant %s of deprecated %s %s.',
$constantName,
strtolower($class->getClassTypeDescription()),
$referencedClass
))->identifier(sprintf('classConstant.deprecated%s', $class->getClassTypeDescription()))->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Fetching class constant %s of deprecated %s %s:\n%s",
$constantName,
strtolower($class->getClassTypeDescription()),
$referencedClass,
$classDescription
))->identifier(sprintf('classConstant.deprecated%s', $class->getClassTypeDescription()))->build();
}
}
if (strtolower($constantName) === 'class') {
continue;
}
if (!$class->hasConstant($constantName)) {
continue;
}
$constantReflection = $class->getConstant($constantName);
if (!$constantReflection->isDeprecated()->yes()) {
continue;
}
$description = $constantReflection->getDeprecatedDescription();
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Fetching deprecated class constant %s of %s %s.',
$constantName,
strtolower($class->getClassTypeDescription()),
$referencedClass
))->identifier('classConstant.deprecated')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Fetching deprecated class constant %s of %s %s:\n%s",
$constantName,
strtolower($class->getClassTypeDescription()),
$referencedClass,
$description
))->identifier('classConstant.deprecated')->build();
}
}
return $errors;
}
}

View File

@@ -0,0 +1,60 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
/**
* @implements Rule<ConstFetch>
*/
class FetchingDeprecatedConstRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return ConstFetch::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if (!$this->reflectionProvider->hasConstant($node->name, $scope)) {
return [];
}
$constantReflection = $this->reflectionProvider->getConstant($node->name, $scope);
if ($constantReflection->isDeprecated()->yes()) {
return [
RuleErrorBuilder::message(sprintf(
$constantReflection->getDeprecatedDescription() ?? 'Use of constant %s is deprecated.',
$constantReflection->getName()
))->identifier('constant.deprecated')->build(),
];
}
return [];
}
}

View File

@@ -0,0 +1,105 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
/**
* @implements Rule<Class_>
*/
class ImplementationOfDeprecatedInterfaceRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return Class_::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$errors = [];
$className = isset($node->namespacedName)
? (string) $node->namespacedName
: (string) $node->name;
try {
$class = $this->reflectionProvider->getClass($className);
} catch (ClassNotFoundException $e) {
return [];
}
if ($class->isDeprecated()) {
return [];
}
foreach ($node->implements as $implement) {
$interfaceName = (string) $implement;
try {
$interface = $this->reflectionProvider->getClass($interfaceName);
if ($interface->isDeprecated()) {
$description = $interface->getDeprecatedDescription();
if (!$class->isAnonymous()) {
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Class %s implements deprecated interface %s.',
$className,
$interfaceName
))->identifier('class.implementsDeprecatedInterface')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Class %s implements deprecated interface %s:\n%s",
$className,
$interfaceName,
$description
))->identifier('class.implementsDeprecatedInterface')->build();
}
} else {
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Anonymous class implements deprecated interface %s.',
$interfaceName
))->identifier('class.implementsDeprecatedInterface')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Anonymous class implements deprecated interface %s:\n%s",
$interfaceName,
$description
))->identifier('class.implementsDeprecatedInterface')->build();
}
}
}
} catch (ClassNotFoundException $e) {
// Other rules will notify if the interface is not found
}
}
return $errors;
}
}

View File

@@ -0,0 +1,102 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
/**
* @implements Rule<Class_>
*/
class InheritanceOfDeprecatedClassRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return Class_::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
if ($node->extends === null) {
return [];
}
$errors = [];
$className = isset($node->namespacedName)
? (string) $node->namespacedName
: (string) $node->name;
try {
$class = $this->reflectionProvider->getClass($className);
} catch (ClassNotFoundException $e) {
return [];
}
$parentClassName = (string) $node->extends;
try {
$parentClass = $this->reflectionProvider->getClass($parentClassName);
$description = $parentClass->getDeprecatedDescription();
if ($parentClass->isDeprecated()) {
if (!$class->isAnonymous()) {
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Class %s extends deprecated class %s.',
$className,
$parentClassName
))->identifier('class.extendsDeprecatedClass')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Class %s extends deprecated class %s:\n%s",
$className,
$parentClassName,
$description
))->identifier('class.extendsDeprecatedClass')->build();
}
} else {
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Anonymous class extends deprecated class %s.',
$parentClassName
))->identifier('class.extendsDeprecatedClass')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Anonymous class extends deprecated class %s:\n%s",
$parentClassName,
$description
))->identifier('class.extendsDeprecatedClass')->build();
}
}
}
} catch (ClassNotFoundException $e) {
// Other rules will notify if the interface is not found
}
return $errors;
}
}

View File

@@ -0,0 +1,84 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
/**
* @implements Rule<Interface_>
*/
class InheritanceOfDeprecatedInterfaceRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
}
public function getNodeType(): string
{
return Interface_::class;
}
public function processNode(Node $node, Scope $scope): array
{
$interfaceName = isset($node->namespacedName)
? (string) $node->namespacedName
: (string) $node->name;
try {
$interface = $this->reflectionProvider->getClass($interfaceName);
} catch (ClassNotFoundException $e) {
return [];
}
if ($interface->isDeprecated()) {
return [];
}
$errors = [];
foreach ($node->extends as $parentInterfaceName) {
$parentInterfaceName = (string) $parentInterfaceName;
try {
$parentInterface = $this->reflectionProvider->getClass($parentInterfaceName);
if (!$parentInterface->isDeprecated()) {
continue;
}
$description = $parentInterface->getDeprecatedDescription();
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Interface %s extends deprecated interface %s.',
$interfaceName,
$parentInterfaceName
))->identifier('interface.extendsDeprecatedInterface')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Interface %s extends deprecated interface %s:\n%s",
$interfaceName,
$parentInterfaceName,
$description
))->identifier('interface.extendsDeprecatedInterface')->build();
}
} catch (ClassNotFoundException $e) {
// Other rules will notify if the interface is not found
}
}
return $errors;
}
}

View File

@@ -0,0 +1,109 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\RuleLevelHelper;
use PHPStan\Type\ErrorType;
use function sprintf;
/**
* @implements Rule<New_>
*/
class InstantiationOfDeprecatedClassRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var RuleLevelHelper */
private $ruleLevelHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, RuleLevelHelper $ruleLevelHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->ruleLevelHelper = $ruleLevelHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return New_::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$referencedClasses = [];
if ($node->class instanceof Name) {
$referencedClasses[] = $scope->resolveName($node->class);
} elseif ($node->class instanceof Class_) {
if (!isset($node->class->namespacedName)) {
return [];
}
$referencedClasses[] = $scope->resolveName($node->class->namespacedName);
} else {
$classTypeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->class,
'', // We don't care about the error message
static function (): bool {
return true;
}
);
if ($classTypeResult->getType() instanceof ErrorType) {
return [];
}
$referencedClasses = $classTypeResult->getReferencedClasses();
}
$errors = [];
foreach ($referencedClasses as $referencedClass) {
try {
$class = $this->reflectionProvider->getClass($referencedClass);
} catch (ClassNotFoundException $e) {
continue;
}
if (!$class->isDeprecated()) {
continue;
}
$description = $class->getDeprecatedDescription();
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Instantiation of deprecated class %s.',
$referencedClass
))->identifier('new.deprecated')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Instantiation of deprecated class %s:\n%s",
$referencedClass,
$description
))->identifier('new.deprecated')->build();
}
}
return $errors;
}
}

View File

@@ -0,0 +1,98 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClassMethodNode;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
use function strtolower;
/**
* @implements Rule<InClassMethodNode>
*/
class TypeHintDeprecatedInClassMethodSignatureRule implements Rule
{
/** @var DeprecatedClassHelper */
private $deprecatedClassHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->deprecatedClassHelper = $deprecatedClassHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return InClassMethodNode::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$method = $node->getMethodReflection();
$methodSignature = ParametersAcceptorSelector::selectSingle($method->getVariants());
$errors = [];
foreach ($methodSignature->getParameters() as $parameter) {
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($parameter->getType()->getReferencedClasses());
foreach ($deprecatedClasses as $deprecatedClass) {
if ($method->getDeclaringClass()->isAnonymous()) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Parameter $%s of method %s() in anonymous class has typehint with deprecated %s %s%s',
$parameter->getName(),
$method->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('parameter.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
'Parameter $%s of method %s::%s() has typehint with deprecated %s %s%s',
$parameter->getName(),
$method->getDeclaringClass()->getName(),
$method->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('parameter.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
}
}
}
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($methodSignature->getReturnType()->getReferencedClasses());
foreach ($deprecatedClasses as $deprecatedClass) {
if ($method->getDeclaringClass()->isAnonymous()) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Return type of method %s() in anonymous class has typehint with deprecated %s %s%s',
$method->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('return.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
'Return type of method %s::%s() has typehint with deprecated %s %s%s',
$method->getDeclaringClass()->getName(),
$method->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('return.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
}
}
return $errors;
}
}

View File

@@ -0,0 +1,75 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InClosureNode;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use function sprintf;
use function strtolower;
/**
* @implements Rule<InClosureNode>
*/
class TypeHintDeprecatedInClosureSignatureRule implements Rule
{
/** @var DeprecatedClassHelper */
private $deprecatedClassHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->deprecatedClassHelper = $deprecatedClassHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return InClosureNode::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$functionSignature = $scope->getAnonymousFunctionReflection();
if ($functionSignature === null) {
throw new ShouldNotHappenException();
}
$errors = [];
foreach ($functionSignature->getParameters() as $parameter) {
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($parameter->getType()->getReferencedClasses());
foreach ($deprecatedClasses as $deprecatedClass) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Parameter $%s of anonymous function has typehint with deprecated %s %s%s',
$parameter->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('parameter.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
}
}
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($functionSignature->getReturnType()->getReferencedClasses());
foreach ($deprecatedClasses as $deprecatedClass) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Return type of anonymous function has typehint with deprecated %s %s%s',
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('return.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
}
return $errors;
}
}

View File

@@ -0,0 +1,79 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Node\InFunctionNode;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use function sprintf;
use function strtolower;
/**
* @implements Rule<InFunctionNode>
*/
class TypeHintDeprecatedInFunctionSignatureRule implements Rule
{
/** @var DeprecatedClassHelper */
private $deprecatedClassHelper;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedClassHelper $deprecatedClassHelper, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->deprecatedClassHelper = $deprecatedClassHelper;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return InFunctionNode::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$function = $scope->getFunction();
if ($function === null) {
throw new ShouldNotHappenException();
}
$functionSignature = ParametersAcceptorSelector::selectSingle($function->getVariants());
$errors = [];
foreach ($functionSignature->getParameters() as $parameter) {
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($parameter->getType()->getReferencedClasses());
foreach ($deprecatedClasses as $deprecatedClass) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Parameter $%s of function %s() has typehint with deprecated %s %s%s',
$parameter->getName(),
$function->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('parameter.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
}
}
$deprecatedClasses = $this->deprecatedClassHelper->filterDeprecatedClasses($functionSignature->getReturnType()->getReferencedClasses());
foreach ($deprecatedClasses as $deprecatedClass) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Return type of function %s() has typehint with deprecated %s %s%s',
$function->getName(),
strtolower($deprecatedClass->getClassTypeDescription()),
$deprecatedClass->getName(),
$this->deprecatedClassHelper->getClassDeprecationDescription($deprecatedClass)
))->identifier(sprintf('return.deprecated%s', $deprecatedClass->getClassTypeDescription()))->build();
}
return $errors;
}
}

View File

@@ -0,0 +1,65 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Expr\Cast;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
/**
* @implements Rule<Cast>
*/
class UsageOfDeprecatedCastRule implements Rule
{
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return Cast::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$castedType = $scope->getType($node->expr);
if (! $castedType->hasMethod('__toString')->yes()) {
return [];
}
$method = $castedType->getMethod('__toString', $scope);
if (! $method->isDeprecated()->yes()) {
return [];
}
$description = $method->getDeprecatedDescription();
if ($description === null) {
return [
RuleErrorBuilder::message(sprintf(
'Casting class %s to string is deprecated.',
$method->getDeclaringClass()->getName()
))->identifier('class.toStringDeprecated')->build(),
];
}
return [
RuleErrorBuilder::message(sprintf(
"Casting class %s to string is deprecated.:\n%s",
$method->getDeclaringClass()->getName(),
$description
))->identifier('class.toStringDeprecated')->build(),
];
}
}

View File

@@ -0,0 +1,84 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Deprecations;
use PhpParser\Node;
use PhpParser\Node\Stmt\TraitUse;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use function sprintf;
/**
* @implements Rule<TraitUse>
*/
class UsageOfDeprecatedTraitRule implements Rule
{
/** @var ReflectionProvider */
private $reflectionProvider;
/** @var DeprecatedScopeHelper */
private $deprecatedScopeHelper;
public function __construct(ReflectionProvider $reflectionProvider, DeprecatedScopeHelper $deprecatedScopeHelper)
{
$this->reflectionProvider = $reflectionProvider;
$this->deprecatedScopeHelper = $deprecatedScopeHelper;
}
public function getNodeType(): string
{
return TraitUse::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->deprecatedScopeHelper->isScopeDeprecated($scope)) {
return [];
}
$classReflection = $scope->getClassReflection();
if ($classReflection === null) {
throw new ShouldNotHappenException();
}
$errors = [];
$className = $classReflection->getName();
foreach ($node->traits as $traitNameNode) {
$traitName = (string) $traitNameNode;
try {
$trait = $this->reflectionProvider->getClass($traitName);
if (!$trait->isDeprecated()) {
continue;
}
$description = $trait->getDeprecatedDescription();
if ($description === null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Usage of deprecated trait %s in class %s.',
$traitName,
$className
))->identifier('traitUse.deprecated')->build();
} else {
$errors[] = RuleErrorBuilder::message(sprintf(
"Usage of deprecated trait %s in class %s:\n%s",
$traitName,
$className,
$description
))->identifier('traitUse.deprecated')->build();
}
} catch (ClassNotFoundException $e) {
continue;
}
}
return $errors;
}
}