apply new static analysis

This commit is contained in:
Tomas Votruba 2019-01-25 01:49:26 +01:00
parent 45df82424c
commit 2c878c7541
40 changed files with 277 additions and 93 deletions

View File

@ -66,9 +66,13 @@ CODE_SAMPLE
return null;
}
/** @var AssignOp|Assign $previousNode */
$previousNode = $node->getAttribute(Attribute::PREVIOUS_NODE)->expr;
$previousNode = $node->getAttribute(Attribute::PREVIOUS_NODE);
if (! $previousNode instanceof Expression) {
return null;
}
/** @var AssignOp|Assign $previousNode */
$previousNode = $previousNode->expr;
$previousVariableNode = $previousNode->var;
// has some comment

View File

@ -8,6 +8,7 @@ use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Name\FullyQualified;
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\PhpParser\NodeTransformer;
@ -108,17 +109,7 @@ CODE_SAMPLE
continue;
}
$yieldNodes = $this->nodeTransformer->transformArrayToYields($arrayNode);
// remove whole return node
$this->removeNode($arrayNode->getAttribute(Attribute::PARENT_NODE));
// remove doc block
$this->docBlockAnalyzer->removeTagFromNode($node, 'return');
// change return typehint
$node->returnType = new FullyQualified(Iterator::class);
$node->stmts = array_merge((array) $node->stmts, $yieldNodes);
$this->transformArrayToYieldsOnMethodNode($node, $arrayNode);
}
}
@ -141,4 +132,25 @@ CODE_SAMPLE
return null;
}
private function transformArrayToYieldsOnMethodNode(ClassMethod $classMethod, Array_ $arrayNode): void
{
$yieldNodes = $this->nodeTransformer->transformArrayToYields($arrayNode);
// remove whole return node
$parentNode = $arrayNode->getAttribute(Attribute::PARENT_NODE);
if ($parentNode === null) {
throw new ShouldNotHappenException();
}
$this->removeNode($parentNode);
// remove doc block
$this->docBlockAnalyzer->removeTagFromNode($classMethod, 'return');
// change return typehint
$classMethod->returnType = new FullyQualified(Iterator::class);
$classMethod->stmts = array_merge((array) $classMethod->stmts, $yieldNodes);
}
}

View File

@ -8,6 +8,7 @@ use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\NodeVisitor\NameResolver;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\Node\BetterNodeFinder;
use Rector\Rector\AbstractRector;
@ -62,8 +63,7 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
$usedNameNodes = $this->resolveUsedNameNodes($parentNode);
$usedNameNodes = $this->resolveUsedNameNodes($node);
if ($usedNameNodes === []) {
return null;
}
@ -100,19 +100,20 @@ CODE_SAMPLE
/**
* @return Node[][][]
*/
private function resolveUsedNameNodes(Node $parentNode): array
private function resolveUsedNameNodes(Use_ $node): array
{
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
if ($parentNode === null) {
throw new ShouldNotHappenException();
}
$usedNameNodes = [];
// assumption for namespaced content
if ($parentNode instanceof Namespace_) {
/** @var Name[] $namedNodes */
$namedNodes = $this->betterNodeFinder->find($parentNode, function (Node $node) {
if ($node instanceof Name) {
return true;
}
return false;
return $node instanceof Name;
});
foreach ($namedNodes as $nameNode) {
@ -124,7 +125,6 @@ CODE_SAMPLE
/** @var Node $parentNode */
$parentNode = $nameNode->getAttribute(Attribute::PARENT_NODE);
$usedNameNodes[$originalName->toString()][] = [$nameNode, $parentNode];
}
}

View File

@ -70,9 +70,12 @@ CODE_SAMPLE
return null;
}
if ($this->classMethodMaintainer->hasParentMethodOrInterfaceMethod(
$node->getAttribute(Attribute::METHOD_NODE)
)) {
$methodNode = $node->getAttribute(Attribute::METHOD_NODE);
if ($methodNode === null) {
return null;
}
if ($this->classMethodMaintainer->hasParentMethodOrInterfaceMethod($methodNode)) {
return null;
}

View File

@ -121,6 +121,10 @@ CODE_SAMPLE
$node = $exprNode->getAttribute(Attribute::PARENT_NODE);
}
if ($node === null) {
return;
}
$this->docBlockAnalyzer->changeType($node, $oldType, $newType);
}

View File

@ -9,6 +9,7 @@ use PhpParser\Node\Stmt\Property;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
use Rector\Application\ErrorAndDiffCollector;
use Rector\Bridge\Contract\AnalyzedApplicationContainerInterface;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockAnalyzer;
use Rector\Rector\AbstractRector;
@ -127,7 +128,12 @@ CODE_SAMPLE
// set to private
$node->flags = Class_::MODIFIER_PRIVATE;
$this->addPropertyToClass($node->getAttribute(Attribute::CLASS_NODE), $type, $name);
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if (! $classNode instanceof Class_) {
throw new ShouldNotHappenException();
}
$this->addPropertyToClass($classNode, $type, $name);
return $node;
}

View File

@ -7,6 +7,7 @@ use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\Node\Stmt\TraitUse;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\Node\Resolver\NameResolver;
@ -39,7 +40,11 @@ final class ClassLikeNodeCollector
public function addClass(Class_ $classNode): void
{
$name = (string) $classNode->getAttribute(Attribute::CLASS_NAME);
$name = $classNode->getAttribute(Attribute::CLASS_NAME);
if ($name === null) {
throw new ShouldNotHappenException();
}
$this->classes[$name] = $classNode;
}
@ -50,13 +55,21 @@ final class ClassLikeNodeCollector
public function addInterface(Interface_ $interfaceNode): void
{
$name = (string) $interfaceNode->getAttribute(Attribute::CLASS_NAME);
$name = $interfaceNode->getAttribute(Attribute::CLASS_NAME);
if ($name === null) {
throw new ShouldNotHappenException();
}
$this->interfaces[$name] = $interfaceNode;
}
public function addTrait(Trait_ $traitNode): void
{
$name = (string) $traitNode->getAttribute(Attribute::CLASS_NAME);
$name = $traitNode->getAttribute(Attribute::CLASS_NAME);
if ($name === null) {
throw new ShouldNotHappenException();
}
$this->traits[$name] = $traitNode;
}
@ -85,11 +98,16 @@ final class ClassLikeNodeCollector
{
$childrenClasses = [];
foreach ($this->classes as $classNode) {
if (! is_a($classNode->getAttribute(Attribute::CLASS_NAME), $class, true)) {
$className = $classNode->getAttribute(Attribute::CLASS_NAME);
if ($className === null) {
return [];
}
if (! is_a($className, $class, true)) {
continue;
}
if ($classNode->getAttribute(Attribute::CLASS_NAME) === $class) {
if ($className === $class) {
continue;
}
@ -106,11 +124,16 @@ final class ClassLikeNodeCollector
{
$implementerInterfaces = [];
foreach ($this->interfaces as $interfaceNode) {
if (! is_a($interfaceNode->getAttribute(Attribute::CLASS_NAME), $interface, true)) {
$className = $interfaceNode->getAttribute(Attribute::CLASS_NAME);
if ($className === null) {
return [];
}
if (! is_a($className, $interface, true)) {
continue;
}
if ($interfaceNode->getAttribute(Attribute::CLASS_NAME) === $interface) {
if ($className === $interface) {
continue;
}

View File

@ -2,7 +2,9 @@
namespace Rector\NodeTypeResolver\Application;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\Node\Resolver\NameResolver;
@ -25,7 +27,11 @@ final class ConstantNodeCollector
public function addConstant(ClassConst $classConst): void
{
$className = (string) $classConst->getAttribute(Attribute::CLASS_NAME);
$className = $classConst->getAttribute(Attribute::CLASS_NAME);
if ($className === null) {
throw new ShouldNotHappenException();
}
$constantName = $this->nameResolver->resolve($classConst);
$this->constantsByType[$className][$constantName] = $classConst;

View File

@ -5,6 +5,7 @@ namespace Rector\NodeTypeResolver\Application;
use Nette\Utils\Strings;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\Node\Resolver\NameResolver;
use ReflectionClass;
@ -33,7 +34,11 @@ final class FunctionLikeNodeCollector
public function addMethod(ClassMethod $classMethodNode): void
{
$className = (string) $classMethodNode->getAttribute(Attribute::CLASS_NAME);
$className = $classMethodNode->getAttribute(Attribute::CLASS_NAME);
if ($className === null) {
throw new ShouldNotHappenException();
}
$methodName = $this->nameResolver->resolve($classMethodNode);
$this->methodsByType[$className][$methodName] = $classMethodNode;

View File

@ -30,6 +30,7 @@ final class Attribute
public const CLASS_NAME = 'className';
/**
* @todo split Class node, interface node and trait node, to be compatible with other SpecificNode|null, values
* @var string
*/
public const CLASS_NODE = 'classNode';

View File

@ -12,6 +12,7 @@ use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\Broker;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverAwareInterface;
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
use Rector\NodeTypeResolver\Node\Attribute;
@ -64,7 +65,7 @@ final class NodeTypeResolver
public function resolve(Node $node): array
{
if ($node instanceof ClassMethod || $node instanceof ClassConst) {
return $this->resolve($node->getAttribute(Attribute::CLASS_NODE));
return $this->resolveClassNode($node);
}
if ($node instanceof StaticCall || $node instanceof ClassConstFetch) {
@ -106,6 +107,20 @@ final class NodeTypeResolver
}
}
/**
* @param ClassConst|ClassMethod $node
* @return string[]
*/
private function resolveClassNode(Node $node): array
{
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if ($classNode === null) {
throw new ShouldNotHappenException();
}
return $this->resolve($classNode);
}
/**
* @return string[]
*/

View File

@ -7,6 +7,7 @@ use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\NodeTypeResolver\Reflection\ClassReflectionTypesResolver;
@ -37,8 +38,10 @@ final class ClassAndInterfaceTypeResolver implements PerNodeTypeResolverInterfac
*/
public function resolve(Node $node): array
{
/** @var Scope $nodeScope */
$nodeScope = $node->getAttribute(Attribute::SCOPE);
if ($nodeScope === null) {
throw new ShouldNotHappenException();
}
/** @var ClassReflection $classReflection */
$classReflection = $nodeScope->getClassReflection();

View File

@ -25,13 +25,23 @@ final class NameTypeResolver implements PerNodeTypeResolverInterface
public function resolve(Node $nameNode): array
{
if ($nameNode->toString() === 'parent') {
return [$nameNode->getAttribute(Attribute::PARENT_CLASS_NAME)];
$parentClassName = $nameNode->getAttribute(Attribute::PARENT_CLASS_NAME);
if ($parentClassName === null) {
return [];
}
return [$parentClassName];
}
return [$this->resolveFullyQualifiedName($nameNode, $nameNode->toString())];
$fullyQualifiedName = $this->resolveFullyQualifiedName($nameNode, $nameNode->toString());
if ($fullyQualifiedName === null) {
return [];
}
return [$fullyQualifiedName];
}
private function resolveFullyQualifiedName(Node $nameNode, string $name): string
private function resolveFullyQualifiedName(Node $nameNode, string $name): ?string
{
if (in_array($name, ['self', 'static', 'this'], true)) {
return $nameNode->getAttribute(Attribute::CLASS_NAME);

View File

@ -24,7 +24,12 @@ final class NamespaceAnalyzer
public function resolveTypeToFullyQualified(string $type, Node $node): string
{
$useStatementMatch = $this->matchUseStatements($type, (array) $node->getAttribute(Attribute::USE_NODES));
$useNodes = $node->getAttribute(Attribute::USE_NODES);
if ($useNodes === null) {
$useNodes = [];
}
$useStatementMatch = $this->matchUseStatements($type, $useNodes);
if ($useStatementMatch) {
return $useStatementMatch;
}

View File

@ -14,6 +14,7 @@ use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\For_;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
@ -150,7 +151,12 @@ CODE_SAMPLE
'stmts' => [new Expression($funcCallNode)],
]);
$this->addNodeAfterNode($forNode, $assignNode->getAttribute(Attribute::PREVIOUS_EXPRESSION));
$previousExpression = $assignNode->getAttribute(Attribute::PREVIOUS_EXPRESSION);
if ($previousExpression === null) {
throw new ShouldNotHappenException();
}
$this->addNodeAfterNode($forNode, $previousExpression);
return $assignNode;
}

View File

@ -6,12 +6,12 @@ use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Scalar\String_;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
use Rector\RectorDefinition\RectorDefinition;
use function Safe\sprintf;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
/**
* @see https://wiki.php.net/rfc/deprecate-bareword-strings
@ -50,8 +50,10 @@ final class BarewordStringRector extends AbstractRector
}
// load the file!
/** @var SmartFileInfo $fileInfo */
$fileInfo = $node->getAttribute(Attribute::FILE_INFO);
if ($fileInfo === null) {
throw new ShouldNotHappenException();
}
$this->undefinedConstants = [];
$previousErrorHandler = set_error_handler(function ($severity, $message, $file, $line): void {

View File

@ -5,7 +5,6 @@ namespace Rector\Php\Rector\FuncCall;
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Expression;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
use Rector\RectorDefinition\CodeSample;
@ -70,7 +69,6 @@ CODE_SAMPLE
*/
public function refactor(Node $node): ?Node
{
/** @var Expression|null $previousExpression */
$previousExpression = $node->getAttribute(Attribute::PREVIOUS_EXPRESSION);
if ($previousExpression === null) {
return null;

View File

@ -6,7 +6,6 @@ use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Expression;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
use Rector\Rector\AbstractRector;
@ -64,17 +63,19 @@ CODE_SAMPLE
return null;
}
if (isset($node->args[1])) {
return null;
}
$resultVariable = new Variable('result');
$node->args[1] = new Arg($resultVariable);
/** @var Expression $expression */
$expression = $node->getAttribute(Attribute::CURRENT_EXPRESSION);
if ($expression === null) {
return null;
}
// @todo maybe solve in generic way as attribute?
$nextExpression = $expression->getAttribute(Attribute::NEXT_NODE);
if ($nextExpression === null) {
return null;
}
$this->callableNodeTraverser->traverseNodesWithCallable([$nextExpression], function (Node $node) use (
$resultVariable

View File

@ -224,6 +224,9 @@ CODE_SAMPLE
private function findAssigners(Node $variableNode): array
{
$methodNode = $variableNode->getAttribute(Attribute::METHOD_NODE);
if ($methodNode === null) {
return [];
}
/** @var Assign[] $assignNode */
return $this->betterNodeFinder->find([$methodNode], function (Node $node) use ($variableNode) {

View File

@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Interface_;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Application\ClassLikeNodeCollector;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\NodeTypeResolver\Php\AbstractTypeInfo;
@ -113,8 +114,10 @@ abstract class AbstractTypeDeclarationRector extends AbstractRector
}
}
/** @var Class_ $classNode */
$classNode = $classMethodNode->getAttribute(Attribute::CLASS_NODE);
if (($classNode instanceof Class_ || $classNode instanceof Interface_) === false) {
return false;
}
$interfaceNames = $this->getClassLikeNodeParentInterfaceNames($classNode);
foreach ($interfaceNames as $interfaceName) {
@ -192,6 +195,10 @@ abstract class AbstractTypeDeclarationRector extends AbstractRector
if ($nakedType->toString() === 'self') {
$className = $node->getAttribute(Attribute::CLASS_NAME);
if ($className === null) {
throw new ShouldNotHappenException();
}
$type = new FullyQualified($className);
return $returnTypeInfo->isNullable() ? new NullableType($type) : $type;
@ -199,6 +206,10 @@ abstract class AbstractTypeDeclarationRector extends AbstractRector
if ($nakedType->toString() === 'parent') {
$parentClassName = $node->getAttribute(Attribute::PARENT_CLASS_NAME);
if ($parentClassName === null) {
throw new ShouldNotHappenException();
}
$type = new FullyQualified($parentClassName);
return $returnTypeInfo->isNullable() ? new NullableType($type) : $type;
@ -215,7 +226,6 @@ abstract class AbstractTypeDeclarationRector extends AbstractRector
private function hasParentClassOrImplementsInterface(ClassMethod $classMethodNode): bool
{
/** @var ClassLike|null $classNode */
$classNode = $classMethodNode->getAttribute(Attribute::CLASS_NODE);
if ($classNode === null) {
return false;

View File

@ -7,6 +7,7 @@ use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\NodeTypeResolver\Node\NodeToStringTypeResolver;
use Rector\NodeTypeResolver\NodeTypeAnalyzer;
@ -133,8 +134,10 @@ CODE_SAMPLE
$types[] = $this->nodeToStringTypeResolver->resolver($propertyDefault);
}
/** @var Class_ $classNode */
$classNode = $propertyNode->getAttribute(Attribute::CLASS_NODE);
if (! $classNode instanceof Class_) {
throw new ShouldNotHappenException();
}
$propertyName = $this->getName($propertyNode);
if ($propertyName === null) {
@ -145,11 +148,9 @@ CODE_SAMPLE
$propertyAssignNodes = $this->betterNodeFinder->find([$classNode], function (Node $node) use (
$propertyName
): bool {
if ($node instanceof Assign) {
if ($node->var instanceof PropertyFetch) {
// is property match
return $this->isName($node->var, $propertyName);
}
if ($node instanceof Assign && $node->var instanceof PropertyFetch) {
// is property match
return $this->isName($node->var, $propertyName);
}
return false;

View File

@ -7,7 +7,9 @@ use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use Rector\Bridge\Contract\AnalyzedApplicationContainerInterface;
use Rector\Exception\ShouldNotHappenException;
use Rector\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
@ -43,12 +45,12 @@ abstract class AbstractToConstructorInjectionRector extends AbstractRector
}
$propertyName = $this->propertyNaming->fqnToVariableName($serviceType);
$classNode = $methodCallNode->getAttribute(Attribute::CLASS_NODE);
if (! $classNode instanceof Class_) {
throw new ShouldNotHappenException();
}
$this->addPropertyToClass(
$methodCallNode->getAttribute(Attribute::CLASS_NODE),
$serviceType,
$propertyName
);
$this->addPropertyToClass($classNode, $serviceType, $propertyName);
return $this->createPropertyFetch('this', $propertyName);
}

View File

@ -5,6 +5,7 @@ namespace Rector\Symfony\Rector\FrameworkBundle;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use Rector\Naming\PropertyNaming;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\Rector\AbstractRector;
@ -94,8 +95,13 @@ CODE_SAMPLE
$parameterName = $stringArgument->value;
$propertyName = $this->propertyNaming->underscoreToName($parameterName);
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if (! $classNode instanceof Class_) {
return null;
}
$this->addPropertyToClass(
$node->getAttribute(Attribute::CLASS_NODE),
$classNode,
'string', // @todo: resolve type from container provider? see parameter autowire compiler pass
$propertyName
);

View File

@ -147,6 +147,9 @@ CODE_SAMPLE
}
$methodNode = $node->getAttribute(Attribute::METHOD_NODE);
if ($methodNode === null) {
return false;
}
return $this->controllerMethodAnalyzer->isAction($methodNode);
}

View File

@ -148,6 +148,7 @@ CODE_SAMPLE
);
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
while ($parentNode instanceof MethodCall) {
if ($this->isName($parentNode, 'add')) {
/** @var Array_ $addOptionsArrayNode */

View File

@ -101,9 +101,15 @@ CODE_SAMPLE
private function getRootMethodCallNode(Node $node): ?Node
{
/** @var Node $node */
$expression = $node->getAttribute(Attribute::CURRENT_EXPRESSION);
if ($expression === null) {
return null;
}
$nextExpression = $expression->getAttribute(Attribute::NEXT_NODE);
if ($nextExpression === null) {
return null;
}
return $this->betterNodeFinder->findFirst([$nextExpression], function (Node $node) {
if (! $node instanceof MethodCall) {

View File

@ -118,6 +118,10 @@ CODE_SAMPLE
}
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if ($classNode === null) {
return null;
}
if (! $this->isTypes($classNode, [$this->twigExtensionClass])) {
return null;
}

View File

@ -5,7 +5,7 @@ includes:
parameters:
# to allow intalling with various phsptan versions without reporting old errors here
# reportUnmatchedIgnoredErrors: false
reportUnmatchedIgnoredErrors: false
level: 7
excludes_analyse:

View File

@ -22,9 +22,7 @@ final class BetterNodeFinder
public function findFirstAncestorInstanceOf(Node $node, string $type): ?Node
{
/** @var Node|null $currentNode */
$currentNode = $node->getAttribute(Attribute::PARENT_NODE);
while ($currentNode !== null) {
if ($currentNode instanceof $type) {
return $currentNode;
@ -86,6 +84,9 @@ final class BetterNodeFinder
public function findFirstPrevious(Node $node, callable $filter): ?Node
{
$node = $node instanceof Expression ? $node : $node->getAttribute(Attribute::CURRENT_EXPRESSION);
if ($node === null) {
return null;
}
$foundNode = $this->findFirst([$node], $filter);
// we found what we need

View File

@ -7,8 +7,9 @@ use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\MagicConst\Dir;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Symfony\Component\Finder\SplFileInfo;
use Symplify\PackageBuilder\FileSystem\SmartFileInfo;
final class ConstExprEvaluatorFactory
{
@ -17,8 +18,10 @@ final class ConstExprEvaluatorFactory
return new ConstExprEvaluator(function (Expr $expr): ?string {
// resolve "__DIR__"
if ($expr instanceof Dir) {
/** @var SplFileInfo $fileInfo */
$fileInfo = $expr->getAttribute(Attribute::FILE_INFO);
if (! $fileInfo instanceof SmartFileInfo) {
throw new ShouldNotHappenException();
}
return $fileInfo->getPath();
}
@ -34,13 +37,16 @@ final class ConstExprEvaluatorFactory
private function resolveClassConstFetch(ClassConstFetch $classConstFetchNode): string
{
$class = $classConstFetchNode->class->getAttribute(Attribute::RESOLVED_NAME)->toString();
$class = $classConstFetchNode->class->getAttribute(Attribute::RESOLVED_NAME);
if ($class === null) {
return '';
}
/** @var Identifier $identifierNode */
$identifierNode = $classConstFetchNode->name;
$constant = $identifierNode->toString();
return $class . '::' . $constant;
return $class->toString() . '::' . $constant;
}
}

View File

@ -39,8 +39,9 @@ final class ChildAndParentClassMaintainer
public function completeParentConstructor(Class_ $classNode, ClassMethod $constructorClassMethodNode): void
{
$parentClassName = (string) $classNode->getAttribute(Attribute::PARENT_CLASS_NAME);
if (! $parentClassName) {
/** @var string|null $parentClassName */
$parentClassName = $classNode->getAttribute(Attribute::PARENT_CLASS_NAME);
if ($parentClassName === null) {
return;
}
@ -114,9 +115,9 @@ final class ChildAndParentClassMaintainer
return $constructMethodNode;
}
/** @var string $parentClassName */
/** @var string|null $parentClassName */
$parentClassName = $classNode->getAttribute(Attribute::PARENT_CLASS_NAME);
if (! $parentClassName) {
if ($parentClassName === null) {
return null;
}

View File

@ -42,17 +42,21 @@ final class ClassMethodMaintainer
public function hasParentMethodOrInterfaceMethod(ClassMethod $classMethod): bool
{
$class = $classMethod->getAttribute(Attribute::CLASS_NAME);
if ($class === null) {
return false;
}
$method = $classMethod->getAttribute(Attribute::METHOD_NAME);
if ($method === null) {
return false;
}
if (! class_exists($class)) {
return false;
}
$parentClass = $class;
while ($parentClass = get_parent_class($parentClass)) {
if (method_exists($parentClass, $method)) {
return true;
}
if ($this->isMethodInParent($class, $method)) {
return true;
}
$implementedInterfaces = class_implements($class);
@ -87,6 +91,19 @@ final class ClassMethodMaintainer
return false;
}
private function isMethodInParent(string $class, string $method): bool
{
$parentClass = $class;
while ($parentClass = get_parent_class($parentClass)) {
if (method_exists($parentClass, $method)) {
return true;
}
}
return false;
}
private function isArrayOfArrays(Node $node): bool
{
if (! $node instanceof Array_) {

View File

@ -47,6 +47,9 @@ final class PropertyMaintainer
public function getAllPropertyFetch(Property $propertyNode): array
{
$classNode = $propertyNode->getAttribute(Attribute::CLASS_NODE);
if ($classNode === null) {
return [];
}
return $this->betterNodeFinder->find($classNode, function (Node $node) use ($propertyNode) {
// itself

View File

@ -3,14 +3,12 @@
namespace Rector\Rector;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\NodeTypeResolver\Node\Attribute;
abstract class AbstractPHPUnitRector extends AbstractRector
{
protected function isInTestClass(Node $node): bool
{
/** @var Class_|null $classNode */
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if ($classNode === null) {
return false;

View File

@ -161,7 +161,6 @@ abstract class AbstractRector extends NodeVisitorAbstract implements PhpRectorIn
protected function notifyNodeChangeFileInfo(Node $node): void
{
/** @var SmartFileInfo|null $fileInfo */
$fileInfo = $node->getAttribute(Attribute::FILE_INFO);
if ($fileInfo === null) {
throw new ShouldNotHappenException(sprintf(

View File

@ -5,6 +5,7 @@ namespace Rector\Rector\Annotation;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use Rector\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Node\Attribute;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockAnalyzer;
use Rector\Rector\AbstractPHPUnitRector;
@ -94,8 +95,11 @@ CODE_SAMPLE
return null;
}
/** @var Node $parentNode */
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
if ($parentNode === null) {
throw new ShouldNotHappenException();
}
$parentNodeTypes = $this->getTypes($parentNode);
foreach ($this->classToAnnotationMap as $type => $annotationMap) {
if (! in_array($type, $parentNodeTypes, true)) {
@ -122,9 +126,9 @@ CODE_SAMPLE
return true;
}
/** @var Node|null $parentNode */
$parentNode = $node->getAttribute(Attribute::PARENT_NODE);
return ! $parentNode;
return $parentNode === null;
}
private function hasAnyAnnotation(Node $node): bool

View File

@ -105,6 +105,10 @@ CODE_SAMPLE
private function addPropertyToCollector(Property $propertyNode): void
{
$classNode = $propertyNode->getAttribute(Attribute::CLASS_NODE);
if (! $classNode instanceof Class_) {
return;
}
$mainPropertyType = $this->getTypes($propertyNode)[0];
$propertyName = $this->getName($propertyNode);
if ($propertyName === null) {

View File

@ -8,6 +8,7 @@ use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use Rector\Bridge\Contract\DoctrineEntityAndRepositoryMapperInterface;
use Rector\Exception\Bridge\RectorProviderException;
use Rector\Exception\ShouldNotHappenException;
@ -123,9 +124,13 @@ CODE_SAMPLE
}
$repositoryFqn = $this->repositoryFqn($node);
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if (! $classNode instanceof Class_) {
return null;
}
$this->addPropertyToClass(
$node->getAttribute(Attribute::CLASS_NODE),
$classNode,
$repositoryFqn,
$this->propertyNaming->fqnToVariableName($repositoryFqn)
);

View File

@ -83,7 +83,12 @@ CODE_SAMPLE
public function refactor(Node $node): ?Node
{
foreach ($this->propertyToVisibilityByClass as $type => $propertyToVisibility) {
if (! $this->isType($node->getAttribute(Attribute::CLASS_NODE), $type)) {
$classNode = $node->getAttribute(Attribute::CLASS_NODE);
if ($classNode === null) {
continue;
}
if (! $this->isType($classNode, $type)) {
continue;
}

View File

@ -2,7 +2,6 @@
namespace Rector\Tests\Rector\Annotation\AnnotationReplacerRector;
use PHPUnit\Framework\TestCase;
use Rector\Rector\Annotation\AnnotationReplacerRector;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
@ -23,6 +22,8 @@ final class ScenarioToTestAnnotationRectorTest extends AbstractRectorTestCase
*/
protected function getRectorConfiguration(): array
{
return [TestCase::class => ['scenario' => 'test']];
return [
'PHPUnit\Framework\TestCase' => ['scenario' => 'test'],
];
}
}