Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,9 @@ services:
-
class: PHPStan\Reflection\BetterReflection\SourceStubber\ReflectionSourceStubberFactory

-
class: PHPStan\Reflection\Deprecation\DeprecationProvider

php8Lexer:
class: PhpParser\Lexer\Emulative
factory: @PHPStan\Parser\LexerFactory::createEmulative()
Expand Down
3 changes: 3 additions & 0 deletions src/Analyser/NodeScopeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
use PHPStan\Reflection\Callables\SimpleImpurePoint;
use PHPStan\Reflection\Callables\SimpleThrowPoint;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Deprecation\DeprecationProvider;
use PHPStan\Reflection\ExtendedMethodReflection;
use PHPStan\Reflection\ExtendedParameterReflection;
use PHPStan\Reflection\ExtendedParametersAcceptor;
Expand Down Expand Up @@ -255,6 +256,7 @@ public function __construct(
private readonly StubPhpDocProvider $stubPhpDocProvider,
private readonly PhpVersion $phpVersion,
private readonly SignatureMapProvider $signatureMapProvider,
private readonly DeprecationProvider $deprecationResolver,
private readonly AttributeReflectionFactory $attributeReflectionFactory,
private readonly PhpDocInheritanceResolver $phpDocInheritanceResolver,
private readonly FileHelper $fileHelper,
Expand Down Expand Up @@ -2140,6 +2142,7 @@ private function createAstClassReflection(Node\Stmt\ClassLike $stmt, string $cla
$this->phpDocInheritanceResolver,
$this->phpVersion,
$this->signatureMapProvider,
$this->deprecationResolver,
$this->attributeReflectionFactory,
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
Expand Down
35 changes: 23 additions & 12 deletions src/Reflection/BetterReflection/BetterReflectionProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Constant\RuntimeConstantReflection;
use PHPStan\Reflection\ConstantReflection;
use PHPStan\Reflection\Deprecation\DeprecationProvider;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\FunctionReflectionFactory;
use PHPStan\Reflection\InitializerExprContext;
Expand Down Expand Up @@ -85,6 +86,7 @@ public function __construct(
private Reflector $reflector,
private FileTypeMapper $fileTypeMapper,
private PhpDocInheritanceResolver $phpDocInheritanceResolver,
private DeprecationProvider $deprecationResolver,
private PhpVersion $phpVersion,
private NativeFunctionReflectionProvider $nativeFunctionReflectionProvider,
private StubPhpDocProvider $stubPhpDocProvider,
Expand Down Expand Up @@ -148,6 +150,7 @@ public function getClass(string $className): ClassReflection
$this->phpDocInheritanceResolver,
$this->phpVersion,
$this->signatureMapProvider,
$this->deprecationResolver,
$this->attributeReflectionFactory,
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
Expand Down Expand Up @@ -243,6 +246,7 @@ public function getAnonymousClassReflection(Node\Stmt\Class_ $classNode, Scope $
$this->phpDocInheritanceResolver,
$this->phpVersion,
$this->signatureMapProvider,
$this->deprecationResolver,
$this->attributeReflectionFactory,
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
Expand Down Expand Up @@ -305,8 +309,11 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection
$phpDocParameterTypes = [];
$phpDocReturnTag = null;
$phpDocThrowsTag = null;
$deprecatedTag = null;
$isDeprecated = false;

$deprecation = $this->deprecationResolver->getFunctionDeprecation($reflectionFunction);
$deprecationDescription = $deprecation === null ? null : $deprecation->getDescription();
$isDeprecated = $deprecation !== null;

$isInternal = false;
$isPure = null;
$asserts = Assertions::createEmpty();
Expand All @@ -327,8 +334,10 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection
$phpDocParameterTypes = array_map(static fn ($tag) => $tag->getType(), $resolvedPhpDoc->getParamTags());
$phpDocReturnTag = $resolvedPhpDoc->getReturnTag();
$phpDocThrowsTag = $resolvedPhpDoc->getThrowsTag();
$deprecatedTag = $resolvedPhpDoc->getDeprecatedTag();
$isDeprecated = $resolvedPhpDoc->isDeprecated();
if (!$isDeprecated) {
$deprecationDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : $deprecationDescription;
$isDeprecated = $resolvedPhpDoc->isDeprecated();
}
$isInternal = $resolvedPhpDoc->isInternal();
$isPure = $resolvedPhpDoc->isPure();
$asserts = Assertions::createFromResolvedPhpDocBlock($resolvedPhpDoc);
Expand All @@ -347,7 +356,7 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection
$phpDocParameterTypes,
$phpDocReturnTag !== null ? $phpDocReturnTag->getType() : null,
$phpDocThrowsTag !== null ? $phpDocThrowsTag->getType() : null,
$deprecatedTag !== null ? $deprecatedTag->getMessage() : null,
$deprecationDescription,
$isDeprecated,
$isInternal,
$reflectionFunction->getFileName() !== false ? $reflectionFunction->getFileName() : null,
Expand Down Expand Up @@ -407,13 +416,15 @@ public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn
$constantValueType = $this->initializerExprTypeResolver->getType($constantReflection->getValueExpression(), InitializerExprContext::fromGlobalConstant($constantReflection));
$docComment = $constantReflection->getDocComment();

$isDeprecated = TrinaryLogic::createNo();
$deprecatedDescription = null;
if ($docComment !== null) {
$deprecation = $this->deprecationResolver->getConstantDeprecation($constantReflection);
$isDeprecated = $deprecation !== null;
$deprecatedDescription = $deprecation === null ? null : $deprecation->getDescription();

if ($isDeprecated === false && $docComment !== null) {
$resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc($fileName, null, null, null, $docComment);
$isDeprecated = TrinaryLogic::createFromBoolean($resolvedPhpDoc->isDeprecated());
$isDeprecated = $resolvedPhpDoc->isDeprecated();

if ($resolvedPhpDoc->isDeprecated() && $resolvedPhpDoc->getDeprecatedTag() !== null) {
if ($isDeprecated && $resolvedPhpDoc->getDeprecatedTag() !== null) {
$deprecatedMessage = $resolvedPhpDoc->getDeprecatedTag()->getMessage();

$matches = Strings::match($deprecatedMessage ?? '', '#^(\d+)\.(\d+)(?:\.(\d+))?$#');
Expand All @@ -423,7 +434,7 @@ public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn
$patch = $matches[3] ?? 0;
$versionId = sprintf('%d%02d%02d', $major, $minor, $patch);

$isDeprecated = TrinaryLogic::createFromBoolean($this->phpVersion->getVersionId() >= $versionId);
$isDeprecated = $this->phpVersion->getVersionId() >= $versionId;
} else {
// filter raw version number messages like in
// https://github.com/JetBrains/phpstorm-stubs/blob/9608c953230b08f07b703ecfe459cc58d5421437/filter/filter.php#L478
Expand All @@ -436,7 +447,7 @@ public function getConstant(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn
$constantName,
$constantValueType,
$fileName,
$isDeprecated,
TrinaryLogic::createFromBoolean($isDeprecated),
$deprecatedDescription,
);
}
Expand Down
49 changes: 40 additions & 9 deletions src/Reflection/ClassReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use PHPStan\PhpDoc\Tag\TemplateTag;
use PHPStan\PhpDoc\Tag\TypeAliasImportTag;
use PHPStan\PhpDoc\Tag\TypeAliasTag;
use PHPStan\Reflection\Deprecation\DeprecationProvider;
use PHPStan\Reflection\Php\PhpClassReflectionExtension;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Reflection\Php\UniversalObjectCratesClassReflectionExtension;
Expand Down Expand Up @@ -161,6 +162,7 @@ public function __construct(
private PhpDocInheritanceResolver $phpDocInheritanceResolver,
private PhpVersion $phpVersion,
private SignatureMapProvider $signatureMapProvider,
private DeprecationProvider $deprecationResolver,
private AttributeReflectionFactory $attributeReflectionFactory,
private array $propertiesClassReflectionExtensions,
private array $methodsClassReflectionExtensions,
Expand Down Expand Up @@ -1079,6 +1081,10 @@ public function getConstant(string $name): ClassConstantReflection
throw new MissingConstantFromReflectionException($this->getName(), $name);
}

$deprecation = $this->deprecationResolver->getClassConstantDeprecation($reflectionConstant);
$deprecatedDescription = $deprecation === null ? null : $deprecation->getDescription();
$isDeprecated = $deprecation !== null;

$declaringClass = $this->reflectionProvider->getClass($reflectionConstant->getDeclaringClass()->getName());
$fileName = $declaringClass->getFileName();
$phpDocType = null;
Expand All @@ -1099,8 +1105,10 @@ public function getConstant(string $name): ClassConstantReflection
);
}

$deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null;
$isDeprecated = $resolvedPhpDoc->isDeprecated();
if (!$isDeprecated) {
$deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null;
$isDeprecated = $resolvedPhpDoc->isDeprecated();
}
$isInternal = $resolvedPhpDoc->isInternal();
$isFinal = $resolvedPhpDoc->isFinal();
$varTags = $resolvedPhpDoc->getVarTags();
Expand Down Expand Up @@ -1210,11 +1218,8 @@ public function getTypeAliases(): array

public function getDeprecatedDescription(): ?string
{
if ($this->deprecatedDescription === null && $this->isDeprecated()) {
$resolvedPhpDoc = $this->getResolvedPhpDoc();
if ($resolvedPhpDoc !== null && $resolvedPhpDoc->getDeprecatedTag() !== null) {
$this->deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag()->getMessage();
}
if ($this->isDeprecated === null) {
$this->resolveDeprecation();
}

return $this->deprecatedDescription;
Expand All @@ -1223,13 +1228,36 @@ public function getDeprecatedDescription(): ?string
public function isDeprecated(): bool
{
if ($this->isDeprecated === null) {
$resolvedPhpDoc = $this->getResolvedPhpDoc();
$this->isDeprecated = $resolvedPhpDoc !== null && $resolvedPhpDoc->isDeprecated();
$this->resolveDeprecation();
}

return $this->isDeprecated;
}

/**
* @phpstan-assert bool $this->isDeprecated
*/
private function resolveDeprecation(): void
{
$deprecation = $this->deprecationResolver->isClassDeprecated($this->reflection);
if ($deprecation !== null) {
$this->isDeprecated = true;
$this->deprecatedDescription = $deprecation->getDescription();
return;
}

$resolvedPhpDoc = $this->getResolvedPhpDoc();

if ($resolvedPhpDoc !== null && $resolvedPhpDoc->isDeprecated()) {
$this->isDeprecated = true;
$this->deprecatedDescription = $resolvedPhpDoc->getDeprecatedTag() !== null ? $resolvedPhpDoc->getDeprecatedTag()->getMessage() : null;
return;
}

$this->isDeprecated = false;
$this->deprecatedDescription = null;
}

public function isBuiltin(): bool
{
return $this->reflection->isInternal();
Expand Down Expand Up @@ -1559,6 +1587,7 @@ public function withTypes(array $types): self
$this->phpDocInheritanceResolver,
$this->phpVersion,
$this->signatureMapProvider,
$this->deprecationResolver,
$this->attributeReflectionFactory,
$this->propertiesClassReflectionExtensions,
$this->methodsClassReflectionExtensions,
Expand Down Expand Up @@ -1590,6 +1619,7 @@ public function withVariances(array $variances): self
$this->phpDocInheritanceResolver,
$this->phpVersion,
$this->signatureMapProvider,
$this->deprecationResolver,
$this->attributeReflectionFactory,
$this->propertiesClassReflectionExtensions,
$this->methodsClassReflectionExtensions,
Expand Down Expand Up @@ -1631,6 +1661,7 @@ public function asFinal(): self
$this->phpDocInheritanceResolver,
$this->phpVersion,
$this->signatureMapProvider,
$this->deprecationResolver,
$this->attributeReflectionFactory,
$this->propertiesClassReflectionExtensions,
$this->methodsClassReflectionExtensions,
Expand Down
27 changes: 27 additions & 0 deletions src/Reflection/Deprecation/ClassConstantDeprecationExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Deprecation;

use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClassConstant;

/**
* This interface allows you to provide custom deprecation information
*
* To register it in the configuration file use the following tag:
*
* ```
* services:
* -
* class: App\PHPStan\MyProvider
* tags:
* - phpstan.classConstantDeprecationExtension
* ```
*
* @api
*/
interface ClassConstantDeprecationExtension
{

public function getClassConstantDeprecation(ReflectionClassConstant $reflection): ?Deprecation;

}
28 changes: 28 additions & 0 deletions src/Reflection/Deprecation/ClassDeprecationExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Deprecation;

use PHPStan\BetterReflection\Reflection\Adapter\ReflectionClass;
use PHPStan\BetterReflection\Reflection\Adapter\ReflectionEnum;

/**
* This interface allows you to provide custom deprecation information
*
* To register it in the configuration file use the following tag:
*
* ```
* services:
* -
* class: App\PHPStan\MyProvider
* tags:
* - phpstan.classDeprecationExtension
* ```
*
* @api
*/
interface ClassDeprecationExtension
{

public function getClassDeprecation(ReflectionClass|ReflectionEnum $reflection): ?Deprecation;

}
27 changes: 27 additions & 0 deletions src/Reflection/Deprecation/ConstantDeprecationExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Deprecation;

use PHPStan\BetterReflection\Reflection\ReflectionConstant;

/**
* This interface allows you to provide custom deprecation information
*
* To register it in the configuration file use the following tag:
*
* ```
* services:
* -
* class: App\PHPStan\MyProvider
* tags:
* - phpstan.constantDeprecationExtension
* ```
*
* @api
*/
interface ConstantDeprecationExtension
{

public function getConstantDeprecation(ReflectionConstant $reflection): ?Deprecation;

}
35 changes: 35 additions & 0 deletions src/Reflection/Deprecation/Deprecation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Deprecation;

/**
* @api
*/
final class Deprecation
{

private ?string $description = null;

private function __construct()
{
}

public static function create(): self
{
return new self();
}

public function getDescription(): ?string
{
return $this->description;
}

public static function createWithDescription(string $description): self
{
$clone = new self();
$clone->description = $description;

return $clone;
}

}
Loading
Loading