mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-19 06:52:51 +02:00
add ResolvedNameReturnTypeExtension and apply
This commit is contained in:
parent
2c878c7541
commit
7c8a88cf73
@ -123,8 +123,11 @@ CODE_SAMPLE
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Node $parentNode */
|
||||
$parentNode = $nameNode->getAttribute(Attribute::PARENT_NODE);
|
||||
if ($parentNode === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$usedNameNodes[$originalName->toString()][] = [$nameNode, $parentNode];
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -42,7 +41,6 @@ CODE_SAMPLE
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var Expression|null $previousExpression */
|
||||
$previousExpression = $node->getAttribute(Attribute::PREVIOUS_EXPRESSION);
|
||||
if ($previousExpression === null) {
|
||||
return null;
|
||||
|
@ -58,7 +58,8 @@ CODE_SAMPLE
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $node->getAttribute(Attribute::CLASS_NODE) instanceof Class_) {
|
||||
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
|
||||
if (! $classNode instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,8 @@ CODE_SAMPLE
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $node->getAttribute(Attribute::CLASS_NODE) instanceof Class_) {
|
||||
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
|
||||
if (! $classNode instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -78,13 +79,12 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $class */
|
||||
$class = $node->getAttribute(Attribute::CLASS_NAME);
|
||||
$methodName = $this->getName($node);
|
||||
if ($methodName === null) {
|
||||
$class = $this->getName($classNode);
|
||||
if ($class === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$methodName = $this->getName($node);
|
||||
if ($this->classMaintainer->hasParentMethodOrInterface($class, $methodName)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\RectorDefinition\ConfiguredCodeSample;
|
||||
@ -130,8 +129,10 @@ CODE_SAMPLE
|
||||
|
||||
private function processParamNode(NullableType $nullableTypeNode, Param $paramNode, string $newType): void
|
||||
{
|
||||
/** @var ClassMethod $classMethodNode */
|
||||
$classMethodNode = $paramNode->getAttribute(Attribute::PARENT_NODE);
|
||||
if ($classMethodNode === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$oldType = $this->namespaceAnalyzer->resolveTypeToFullyQualified(
|
||||
(string) $nullableTypeNode->type,
|
||||
|
@ -7,6 +7,7 @@ use PhpParser\Node\Expr\Variable;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\TrinaryLogic;
|
||||
use PHPStan\Type\ThisType;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockAnalyzer;
|
||||
@ -54,11 +55,15 @@ final class VariableTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
public function resolve(Node $variableNode): array
|
||||
{
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $variableNode->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
/** @var string $variableName */
|
||||
$variableName = $this->nameResolver->resolve($variableNode);
|
||||
if ($variableName === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($nodeScope->hasVariableType($variableName) === TrinaryLogic::createYes()) {
|
||||
$type = $nodeScope->getVariableType($variableName);
|
||||
|
@ -7,8 +7,8 @@ use PhpParser\Comment\Doc;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Nop;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -49,10 +49,11 @@ CODE_SAMPLE
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
/** @var Expression $expression */
|
||||
$expression = $node->getAttribute(Attribute::CURRENT_EXPRESSION);
|
||||
if ($expression === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
/** @var Node|null $nextNode */
|
||||
$nextNode = $expression->getAttribute(Attribute::NEXT_NODE);
|
||||
if ($nextNode === null) {
|
||||
return null;
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Rector\PHPStan\Rector\Cast;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\Expr\Cast\Array_;
|
||||
use PhpParser\Node\Expr\Cast\Bool_;
|
||||
@ -11,15 +10,12 @@ use PhpParser\Node\Expr\Cast\Double;
|
||||
use PhpParser\Node\Expr\Cast\Int_;
|
||||
use PhpParser\Node\Expr\Cast\Object_;
|
||||
use PhpParser\Node\Expr\Cast\String_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\BooleanType;
|
||||
use PHPStan\Type\FloatType;
|
||||
use PHPStan\Type\IntegerType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
use Rector\RectorDefinition\RectorDefinition;
|
||||
@ -79,21 +75,16 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
$nodeType = $this->getNodeType($node->expr);
|
||||
$sameNodeType = $this->castClassToNodeType[$nodeClass];
|
||||
$nodeType = $this->getStaticType($node->expr);
|
||||
if ($nodeType === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$sameNodeType = $this->castClassToNodeType[$nodeClass];
|
||||
if (! is_a($nodeType, $sameNodeType, true)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $node->expr;
|
||||
}
|
||||
|
||||
private function getNodeType(Expr $node): Type
|
||||
{
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
|
||||
return $nodeScope->getType($node);
|
||||
}
|
||||
}
|
||||
|
@ -173,7 +173,11 @@ CODE_SAMPLE
|
||||
|
||||
private function processClassConstFetch(Expr $expr): void
|
||||
{
|
||||
$className = (string) $expr->getAttribute(Attribute::CLASS_NAME);
|
||||
$className = $expr->getAttribute(Attribute::CLASS_NAME);
|
||||
if (! is_string($className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$constantName = $this->getName($expr);
|
||||
if ($constantName === null) {
|
||||
return;
|
||||
|
@ -7,6 +7,7 @@ use PhpParser\Node\Expr\Cast\String_;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -70,8 +71,11 @@ CODE_SAMPLE
|
||||
// is argument string?
|
||||
$needleArgNode = $node->args[1]->value;
|
||||
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $needleArgNode->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
if ($nodeScope->getType($needleArgNode) instanceof ConstantStringType) {
|
||||
return null;
|
||||
}
|
||||
|
@ -83,9 +83,7 @@ abstract class AbstractTypeDeclarationRector extends AbstractRector
|
||||
}
|
||||
|
||||
$methodName = $this->getName($classMethodNode);
|
||||
if ($methodName === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @todo extract to some "inherited parent method" service
|
||||
|
||||
/** @var string|null $parentClassName */
|
||||
|
@ -79,8 +79,10 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var Class_ $classNode */
|
||||
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
|
||||
if (! $classNode instanceof Class_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// anonymous class → skip
|
||||
if ($classNode->name === null || $node->isAbstract() || $node->isStatic()) {
|
||||
@ -148,7 +150,7 @@ CODE_SAMPLE
|
||||
/** @var ClassMethod[] $classMethodNodes */
|
||||
$classMethodNodes = $this->betterNodeFinder->findInstanceOf($classNode->stmts, ClassMethod::class);
|
||||
foreach ($classMethodNodes as $classMethodNode) {
|
||||
$classMethodNames[] = (string) $classMethodNode->name;
|
||||
$classMethodNames[] = $this->getName($classMethodNode);
|
||||
}
|
||||
|
||||
return $classMethodNames;
|
||||
|
@ -8,6 +8,7 @@ use PhpParser\Node\Stmt\Class_;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\Php\ReturnTypeInfo;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -149,11 +150,15 @@ CODE_SAMPLE
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var string $methodName */
|
||||
$methodName = $this->getName($node);
|
||||
if ($methodName === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
/** @var string $className */
|
||||
$className = $node->getAttribute(Attribute::CLASS_NAME);
|
||||
if (! is_string($className)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$childrenClassLikes = $this->classLikeNodeCollector->findClassesAndInterfacesByType($className);
|
||||
|
||||
|
@ -79,8 +79,10 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var string $className */
|
||||
$className = $node->getAttribute(Attribute::CLASS_NAME);
|
||||
if (! is_string($className)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$methodName = $this->getName($node);
|
||||
if ($methodName === null) {
|
||||
|
@ -104,7 +104,9 @@ CODE_SAMPLE
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->getName($node->class) === $node->getAttribute(Attribute::PARENT_CLASS_NAME)) {
|
||||
$className = $this->getName($node->class);
|
||||
$parentClassName = $node->getAttribute(Attribute::PARENT_CLASS_NAME);
|
||||
if ($className === $parentClassName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -6,15 +6,37 @@ use Nette\Utils\Strings;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use function Safe\sprintf;
|
||||
|
||||
final class TemplateGuesser
|
||||
{
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
public function __construct(NameResolver $nameResolver)
|
||||
{
|
||||
$this->nameResolver = $nameResolver;
|
||||
}
|
||||
|
||||
public function resolveFromClassMethodNode(ClassMethod $classMethodNode, int $version = 5): string
|
||||
{
|
||||
$namespace = (string) $classMethodNode->getAttribute(Attribute::NAMESPACE_NAME);
|
||||
$class = (string) $classMethodNode->getAttribute(Attribute::CLASS_NAME);
|
||||
$method = (string) $classMethodNode->name;
|
||||
$namespace = $classMethodNode->getAttribute(Attribute::NAMESPACE_NAME);
|
||||
if (! is_string($namespace)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$class = $classMethodNode->getAttribute(Attribute::CLASS_NAME);
|
||||
if (! is_string($class)) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$method = $this->nameResolver->resolve($classMethodNode);
|
||||
if ($method === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
if ($version === 3) {
|
||||
return $this->resolveForVersion3($namespace, $class, $method);
|
||||
|
@ -8,6 +8,7 @@ use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Type\Constant\ConstantStringType;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -72,8 +73,11 @@ final class ParseFileRector extends AbstractRector
|
||||
}
|
||||
|
||||
// try to detect current value
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $possibleFileNode->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$nodeType = $nodeScope->getType($possibleFileNode);
|
||||
|
||||
if ($nodeType instanceof ConstantStringType) {
|
||||
|
11
phpstan.neon
11
phpstan.neon
@ -1,4 +1,5 @@
|
||||
includes:
|
||||
- 'utils/phpstan/config/phpstan-extensions.neon'
|
||||
- 'vendor/symplify/phpstan-extensions/config/config.neon'
|
||||
- 'vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon'
|
||||
- 'vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon'
|
||||
@ -70,7 +71,6 @@ parameters:
|
||||
- '#Method Rector\\CodeQuality\\Rector\\Foreach_\\SimplifyForeachToCoalescingRector\:\:matchReturnOrAssignNode\(\) should return PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Stmt\\Return_\|null but returns PhpParser\\Node\|null#'
|
||||
- '#Access to an undefined property PhpParser\\Node::\$(\w+)#'
|
||||
- '#Parameter \#2 \$boolConstFetchNode of method Rector\\CodeQuality\\Rector\\Identical\\SimplifyArraySearchRector::resolveIsNot\(\) expects PhpParser\\Node\\Expr\\ConstFetch, PhpParser\\Node given#'
|
||||
- '#Method Rector\\PhpParser\\Node\\BetterNodeFinder::findFirstAncestorInstanceOf\(\) should return PhpParser\\Node\|null but returns object#'
|
||||
|
||||
# false positive, resolved in previous method
|
||||
- '#Parameter (.*?) of method Rector\\PhpParser\\Node\\Maintainer\\IdentifierMaintainer\:\:(.*?)\(\) expects PhpParser\\Node\\Expr\\ClassConstFetch\|PhpParser\\Node\\Expr\\MethodCall\|PhpParser\\Node\\Expr\\PropertyFetch\|PhpParser\\Node\\Expr\\StaticCall\|PhpParser\\Node\\Stmt\\ClassMethod, PhpParser\\Node given#'
|
||||
@ -98,12 +98,3 @@ parameters:
|
||||
# known values
|
||||
- '#Parameter \#(1|2) \$(left|right) of class PhpParser\\Node\\Expr\\BinaryOp\\Coalesce constructor expects PhpParser\\Node\\Expr, PhpParser\\Node\\Expr\|null given#'
|
||||
- '#Strict comparison using === between PhpParser\\Node\\Expr and null will always evaluate to false#'
|
||||
- '#Cannot cast array<string>\|string\|null to string#'
|
||||
|
||||
# false positive on anonymous classes
|
||||
- '#http\:\/\/bit\.ly\/typehintarray#'
|
||||
|
||||
services:
|
||||
- { class: Symplify\PHPStanExtensions\Type\SplFileInfoTolerantDynamicMethodReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] }
|
||||
# $node->geAttribute($1) => Type|null by $1
|
||||
- { class: Rector\PHPStanExtensions\Rector\Type\GetAttributeReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] }
|
||||
|
@ -7,6 +7,7 @@ use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Broker\Broker;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
@ -60,8 +61,10 @@ final class PropertyFetchMaintainer
|
||||
|
||||
private function hasPublicProperty(PropertyFetch $node, string $propertyName): bool
|
||||
{
|
||||
/** @var Scope $nodeScope */
|
||||
$nodeScope = $node->getAttribute(Attribute::SCOPE);
|
||||
if ($nodeScope === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$propertyFetchType = $nodeScope->getType($node->var);
|
||||
if ($propertyFetchType instanceof ObjectType) {
|
||||
|
@ -104,12 +104,11 @@ CODE_SAMPLE
|
||||
}
|
||||
|
||||
$paramNodeTypes = $this->getTypes($paramNode);
|
||||
$paramName = $this->getName($paramNode->var);
|
||||
if ($paramName === null) {
|
||||
continue;
|
||||
}
|
||||
$paramNodeType = $paramNodeTypes[0] ?? 'mixed';
|
||||
|
||||
$this->addPropertyToClass($classNode, $paramNodeTypes[0], $paramName);
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->getName($paramNode->var);
|
||||
$this->addPropertyToClass($classNode, $paramNodeType, $paramName);
|
||||
|
||||
// remove arguments
|
||||
unset($classMethodNode->params[$key]);
|
||||
|
@ -109,12 +109,8 @@ CODE_SAMPLE
|
||||
return;
|
||||
}
|
||||
|
||||
$mainPropertyType = $this->getTypes($propertyNode)[0];
|
||||
$mainPropertyType = $this->getTypes($propertyNode)[0] ?? 'mixed';
|
||||
$propertyName = $this->getName($propertyNode);
|
||||
if ($propertyName === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->addPropertyToClass($classNode, $mainPropertyType, $propertyName);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use Rector\Configuration\Rector\Architecture\DependencyInjection\VariablesToPropertyFetchCollection;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\RectorDefinition\CodeSample;
|
||||
@ -108,7 +109,12 @@ CODE_SAMPLE
|
||||
|
||||
private function isInControllerActionMethod(Node $node): bool
|
||||
{
|
||||
if (! Strings::endsWith((string) $node->getAttribute(Attribute::CLASS_NAME), 'Controller')) {
|
||||
$className = $node->getAttribute(Attribute::CLASS_NAME);
|
||||
if ($className === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
if (! Strings::endsWith($className, 'Controller')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,8 @@ namespace Rector\Rector\MethodBody;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\Attribute;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockAnalyzer;
|
||||
use Rector\Rector\AbstractRector;
|
||||
@ -97,8 +97,11 @@ CODE_SAMPLE
|
||||
|
||||
$this->removeNode($node);
|
||||
|
||||
/** @var ClassMethod $methodNode */
|
||||
$methodNode = $node->getAttribute(Attribute::METHOD_NODE);
|
||||
if ($methodNode === null) {
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
$this->docBlockAnalyzer->removeTagFromNode($methodNode, 'return');
|
||||
|
||||
return null;
|
||||
|
9
utils/phpstan/config/phpstan-extensions.neon
Normal file
9
utils/phpstan/config/phpstan-extensions.neon
Normal file
@ -0,0 +1,9 @@
|
||||
services:
|
||||
- { class: Symplify\PHPStanExtensions\Type\SplFileInfoTolerantDynamicMethodReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] }
|
||||
# $node->geAttribute($1) => Type|null by $1
|
||||
- { class: Rector\PHPStanExtensions\Rector\Type\GetAttributeReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] }
|
||||
|
||||
# $nameResolver->resolve() => in some cases always string
|
||||
- { class: Rector\PHPStanExtensions\Rector\Type\NameResolverReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] }
|
||||
# $nameResolverTrait->getName() => in some cases always string
|
||||
- { class: Rector\PHPStanExtensions\Rector\Type\NameResolverTraitReturnTypeExtension, tags: [phpstan.broker.dynamicMethodReturnTypeExtension] }
|
@ -0,0 +1,64 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Rector\Type;
|
||||
|
||||
use PhpParser\Node\Const_ as NodeConst;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Const_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\PropertyProperty;
|
||||
use PhpParser\Node\Stmt\Static_;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||
use PHPStan\Type\DynamicMethodReturnTypeExtension;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\StringType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Rector\Rector\NameResolverTrait;
|
||||
|
||||
/**
|
||||
* @see NameResolver::resolve()
|
||||
* @see NameResolverTrait::getName()
|
||||
*
|
||||
* These returns always strings for nodes with required names, e.g. for @see ClassMethod
|
||||
*/
|
||||
abstract class AbstractResolvedNameReturnTypeExtension implements DynamicMethodReturnTypeExtension
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $alwaysNamedTypes = [
|
||||
ClassMethod::class,
|
||||
Trait_::class,
|
||||
Interface_::class,
|
||||
Property::class,
|
||||
PropertyProperty::class,
|
||||
Const_::class,
|
||||
NodeConst::class,
|
||||
Param::class,
|
||||
Name::class,
|
||||
];
|
||||
|
||||
public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type
|
||||
{
|
||||
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
|
||||
|
||||
$argumentValueType = $scope->getType($methodCall->args[0]->value);
|
||||
if ( ! $argumentValueType instanceof ObjectType) {
|
||||
return $returnType;
|
||||
}
|
||||
|
||||
if (in_array($argumentValueType->getClassName(), $this->alwaysNamedTypes, true)) {
|
||||
return new StringType();
|
||||
}
|
||||
|
||||
return $returnType;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Rector\Type;
|
||||
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
|
||||
final class NameResolverReturnTypeExtension extends AbstractResolvedNameReturnTypeExtension
|
||||
{
|
||||
public function getClass(): string
|
||||
{
|
||||
return NameResolver::class;
|
||||
}
|
||||
|
||||
public function isMethodSupported(MethodReflection $methodReflection): bool
|
||||
{
|
||||
return $methodReflection->getName() === 'resolve';
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPStanExtensions\Rector\Type;
|
||||
|
||||
use PHPStan\Reflection\MethodReflection;
|
||||
use Rector\Rector\AbstractRector;
|
||||
use Rector\Rector\NameResolverTrait;
|
||||
|
||||
final class NameResolverTraitReturnTypeExtension extends AbstractResolvedNameReturnTypeExtension
|
||||
{
|
||||
/**
|
||||
* Original scope @see NameResolverTrait
|
||||
*/
|
||||
public function getClass(): string
|
||||
{
|
||||
return AbstractRector::class;
|
||||
}
|
||||
|
||||
public function isMethodSupported(MethodReflection $methodReflection): bool
|
||||
{
|
||||
return $methodReflection->getName() === 'getName';
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user