2019-10-13 05:59:52 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2022-06-06 17:12:56 +00:00
namespace Rector\NodeTypeResolver\PHPStan\Scope ;
2018-08-03 18:41:30 +00:00
2022-06-06 17:12:56 +00:00
use PhpParser\Node ;
use PhpParser\Node\Arg ;
use PhpParser\Node\Expr ;
2022-11-16 14:19:15 +00:00
use PhpParser\Node\Expr\Array_ ;
2022-07-27 08:02:59 +00:00
use PhpParser\Node\Expr\ArrayItem ;
2022-06-06 17:12:56 +00:00
use PhpParser\Node\Expr\Assign ;
2022-06-19 08:24:30 +00:00
use PhpParser\Node\Expr\AssignOp ;
use PhpParser\Node\Expr\BinaryOp ;
2023-06-14 13:54:50 +00:00
use PhpParser\Node\Expr\CallLike ;
2023-04-12 13:24:05 +00:00
use PhpParser\Node\Expr\Cast ;
2023-06-17 06:21:36 +00:00
use PhpParser\Node\Expr\ClassConstFetch ;
use PhpParser\Node\Expr\ConstFetch ;
2022-07-27 08:02:59 +00:00
use PhpParser\Node\Expr\FuncCall ;
2023-06-17 06:21:36 +00:00
use PhpParser\Node\Expr\MethodCall ;
use PhpParser\Node\Expr\New_ ;
use PhpParser\Node\Expr\NullsafeMethodCall ;
use PhpParser\Node\Expr\PropertyFetch ;
use PhpParser\Node\Expr\StaticCall ;
use PhpParser\Node\Expr\StaticPropertyFetch ;
2022-06-19 08:24:30 +00:00
use PhpParser\Node\Expr\Ternary ;
2022-06-20 07:09:14 +00:00
use PhpParser\Node\Expr\Variable ;
2023-03-23 23:21:34 +00:00
use PhpParser\Node\Identifier ;
2023-06-17 04:55:00 +00:00
use PhpParser\Node\IntersectionType ;
2022-06-06 17:12:56 +00:00
use PhpParser\Node\Name ;
2023-06-17 04:55:00 +00:00
use PhpParser\Node\NullableType ;
2022-06-06 17:12:56 +00:00
use PhpParser\Node\Stmt ;
2023-10-27 13:02:33 +00:00
use PhpParser\Node\Stmt\Catch_ ;
2022-06-06 17:12:56 +00:00
use PhpParser\Node\Stmt\Class_ ;
use PhpParser\Node\Stmt\Enum_ ;
2022-07-18 23:37:02 +00:00
use PhpParser\Node\Stmt\EnumCase ;
2022-07-03 17:06:40 +00:00
use PhpParser\Node\Stmt\Expression ;
2022-06-06 17:12:56 +00:00
use PhpParser\Node\Stmt\Finally_ ;
use PhpParser\Node\Stmt\Foreach_ ;
use PhpParser\Node\Stmt\Interface_ ;
use PhpParser\Node\Stmt\Property ;
use PhpParser\Node\Stmt\Return_ ;
use PhpParser\Node\Stmt\Switch_ ;
use PhpParser\Node\Stmt\Trait_ ;
use PhpParser\Node\Stmt\TryCatch ;
2023-06-17 04:55:00 +00:00
use PhpParser\Node\UnionType ;
2022-06-06 17:12:56 +00:00
use PhpParser\NodeTraverser ;
use PHPStan\Analyser\MutatingScope ;
use PHPStan\Analyser\NodeScopeResolver ;
use PHPStan\Analyser\ScopeContext ;
use PHPStan\Node\UnreachableStatementNode ;
use PHPStan\Reflection\ReflectionProvider ;
2022-06-25 16:12:40 +00:00
use PHPStan\Type\ObjectType ;
use PHPStan\Type\TypeCombinator ;
2024-01-02 02:40:38 +00:00
use Rector\Exception\ShouldNotHappenException ;
use Rector\NodeAnalyzer\ClassAnalyzer ;
2022-06-20 07:09:14 +00:00
use Rector\NodeNameResolver\NodeNameResolver ;
2022-06-06 17:12:56 +00:00
use Rector\NodeTypeResolver\Node\AttributeKey ;
2023-05-14 10:54:13 +00:00
use Rector\NodeTypeResolver\PHPStan\Scope\Contract\NodeVisitor\ScopeResolverNodeVisitorInterface ;
2024-01-02 02:40:38 +00:00
use Rector\PhpParser\Node\CustomNode\FileWithoutNamespace ;
use Rector\PHPStan\NodeVisitor\ExprScopeFromStmtNodeVisitor ;
use Rector\PHPStan\NodeVisitor\WrappedNodeRestoringNodeVisitor ;
use Rector\Util\Reflection\PrivatesAccessor ;
2024-02-11 00:29:29 +00:00
use Throwable ;
2024-04-01 16:51:34 +00:00
use RectorPrefix202404\Webmozart\Assert\Assert ;
2018-08-03 18:41:30 +00:00
/**
* @ inspired by https :// github . com / silverstripe / silverstripe - upgrader / blob / 532182 b23e854d02e0b27e68ebc394f436de0682 / src / UpgradeRule / PHP / Visitor / PHPStanScopeVisitor . php
* - https :// github . com / silverstripe / silverstripe - upgrader / pull / 57 / commits / e5c7cfa166ad940d9d4ff69537d9f7608e992359 #diff-5e0807bb3dc03d6a8d8b6ad049abd774
*/
2020-06-16 19:43:45 +00:00
final class PHPStanNodeScopeResolver
2018-08-03 18:41:30 +00:00
{
2018-11-06 23:05:21 +00:00
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2021-08-23 00:20:32 +00:00
* @ var \PHPStan\Analyser\NodeScopeResolver
2018-11-06 23:05:21 +00:00
*/
2021-05-10 23:39:21 +00:00
private $nodeScopeResolver ;
2019-05-12 08:19:38 +00:00
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2021-08-23 00:20:32 +00:00
* @ var \PHPStan\Reflection\ReflectionProvider
2019-05-12 08:19:38 +00:00
*/
2021-05-10 23:39:21 +00:00
private $reflectionProvider ;
2020-04-01 01:55:44 +00:00
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2021-05-10 23:39:21 +00:00
* @ var \Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory
2020-04-01 01:55:44 +00:00
*/
2021-05-10 23:39:21 +00:00
private $scopeFactory ;
2021-06-25 17:38:41 +00:00
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2024-01-02 02:40:38 +00:00
* @ var \Rector\Util\Reflection\PrivatesAccessor
2021-06-25 17:38:41 +00:00
*/
2021-06-26 18:33:28 +00:00
private $privatesAccessor ;
2022-06-20 07:09:14 +00:00
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2022-06-20 07:09:14 +00:00
* @ var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver ;
2023-02-19 17:53:18 +00:00
/**
2023-06-11 23:01:39 +00:00
* @ readonly
2024-01-02 02:40:38 +00:00
* @ var \Rector\NodeAnalyzer\ClassAnalyzer
2023-02-19 17:53:18 +00:00
*/
private $classAnalyzer ;
2023-06-08 22:00:17 +00:00
/**
* @ var string
*/
private const CONTEXT = 'context' ;
/**
* @ readonly
* @ var \PhpParser\NodeTraverser
*/
private $nodeTraverser ;
2023-07-04 13:33:50 +00:00
/**
* @ var bool
*/
private $hasUnreachableStatementNode = \false ;
2023-05-14 10:54:13 +00:00
/**
* @ param ScopeResolverNodeVisitorInterface [] $nodeVisitors
*/
2023-08-11 11:32:21 +00:00
public function __construct ( NodeScopeResolver $nodeScopeResolver , ReflectionProvider $reflectionProvider , iterable $nodeVisitors , \Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory $scopeFactory , PrivatesAccessor $privatesAccessor , NodeNameResolver $nodeNameResolver , ClassAnalyzer $classAnalyzer )
2021-05-09 20:15:43 +00:00
{
2020-06-16 19:43:45 +00:00
$this -> nodeScopeResolver = $nodeScopeResolver ;
2020-01-13 13:34:18 +00:00
$this -> reflectionProvider = $reflectionProvider ;
2021-05-10 23:39:21 +00:00
$this -> scopeFactory = $scopeFactory ;
2021-06-26 18:33:28 +00:00
$this -> privatesAccessor = $privatesAccessor ;
2022-06-20 07:09:14 +00:00
$this -> nodeNameResolver = $nodeNameResolver ;
2023-02-19 17:53:18 +00:00
$this -> classAnalyzer = $classAnalyzer ;
2023-03-28 19:22:16 +00:00
$this -> nodeTraverser = new NodeTraverser ();
2023-05-14 10:54:13 +00:00
foreach ( $nodeVisitors as $nodeVisitor ) {
$this -> nodeTraverser -> addVisitor ( $nodeVisitor );
}
2018-08-03 18:41:30 +00:00
}
/**
2021-10-27 08:50:45 +00:00
* @ param Stmt [] $stmts
2021-06-22 17:07:57 +00:00
* @ return Stmt []
2018-08-03 18:41:30 +00:00
*/
2022-09-01 09:30:44 +00:00
public function processNodes ( array $stmts , string $filePath , ? MutatingScope $formerMutatingScope = null ) : array
2018-08-03 18:41:30 +00:00
{
2022-05-12 09:11:03 +00:00
/**
* The stmts must be array of Stmt , or it will be silently skipped by PHPStan
* @ see vendor / phpstan / phpstan / phpstan . phar / src / Analyser / NodeScopeResolver . php : 282
*/
2022-06-07 08:22:29 +00:00
Assert :: allIsInstanceOf ( $stmts , Stmt :: class );
2023-06-27 20:26:20 +00:00
$this -> nodeTraverser -> traverse ( $stmts );
2022-09-01 09:30:44 +00:00
$scope = $formerMutatingScope ? ? $this -> scopeFactory -> createFromFile ( $filePath );
2018-11-06 23:05:21 +00:00
// skip chain method calls, performance issue: https://github.com/phpstan/phpstan/issues/254
2023-07-20 05:58:46 +00:00
$nodeCallback = function ( Node $node , MutatingScope $mutatingScope ) use ( & $nodeCallback , $filePath ) : void {
2023-06-27 20:26:20 +00:00
if ( $node instanceof FileWithoutNamespace ) {
2023-10-05 12:57:01 +00:00
$node -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2024-02-08 07:30:40 +00:00
$this -> nodeScopeResolverProcessNodes ( $node -> stmts , $mutatingScope , $nodeCallback );
2023-06-27 20:26:20 +00:00
return ;
}
2023-07-01 23:02:38 +00:00
if (( $node instanceof Expression || $node instanceof Return_ || $node instanceof EnumCase || $node instanceof Cast ) && $node -> expr instanceof Expr ) {
2022-07-03 17:06:40 +00:00
$node -> expr -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof Assign || $node instanceof AssignOp ) {
2023-06-14 14:21:17 +00:00
$this -> processAssign ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof Ternary ) {
2022-06-19 08:24:30 +00:00
$this -> processTernary ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof BinaryOp ) {
2022-06-19 08:24:30 +00:00
$this -> processBinaryOp ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof Arg ) {
2022-06-07 08:22:29 +00:00
$node -> value -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof Foreach_ ) {
2022-05-04 15:20:50 +00:00
// decorate value as well
2022-06-07 08:22:29 +00:00
$node -> valueVar -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2022-11-16 14:19:15 +00:00
if ( $node -> valueVar instanceof Array_ ) {
$this -> processArray ( $node -> valueVar , $mutatingScope );
}
2023-08-12 23:39:23 +00:00
} elseif ( $node instanceof Array_ ) {
2022-11-16 14:19:15 +00:00
$this -> processArray ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof Property ) {
2022-06-19 08:24:30 +00:00
$this -> processProperty ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof Switch_ ) {
2022-07-18 14:32:34 +00:00
$this -> processSwitch ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof TryCatch ) {
2023-10-27 17:46:00 +00:00
$this -> processTryCatch ( $node , $mutatingScope );
2023-10-27 13:02:33 +00:00
} elseif ( $node instanceof Catch_ ) {
$this -> processCatch ( $node , $filePath , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof ArrayItem ) {
2022-07-27 08:02:59 +00:00
$this -> processArrayItem ( $node , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof NullableType ) {
2023-06-17 04:55:00 +00:00
$node -> type -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof UnionType || $node instanceof IntersectionType ) {
2023-06-17 04:55:00 +00:00
foreach ( $node -> types as $type ) {
$type -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
2023-08-12 23:39:23 +00:00
} elseif ( $node instanceof StaticPropertyFetch || $node instanceof ClassConstFetch ) {
2023-06-17 06:21:36 +00:00
$node -> class -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
$node -> name -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof PropertyFetch ) {
2023-06-17 06:21:36 +00:00
$node -> var -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
$node -> name -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-11 16:45:13 +00:00
} elseif ( $node instanceof ConstFetch ) {
2023-06-17 06:21:36 +00:00
$node -> name -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-12 23:39:23 +00:00
} elseif ( $node instanceof CallLike ) {
$this -> processCallike ( $node , $mutatingScope );
2023-06-17 06:21:36 +00:00
}
2022-06-07 08:22:29 +00:00
if ( $node instanceof Trait_ ) {
2023-08-14 09:58:25 +00:00
$this -> processTrait ( $node , $mutatingScope , $nodeCallback );
2019-08-05 16:52:55 +00:00
return ;
2018-08-03 18:41:30 +00:00
}
2021-03-18 01:48:44 +00:00
// the class reflection is resolved AFTER entering to class node
// so we need to get it from the first after this one
2022-06-07 08:22:29 +00:00
if ( $node instanceof Class_ || $node instanceof Interface_ || $node instanceof Enum_ ) {
2022-04-10 08:30:09 +00:00
/** @var MutatingScope $mutatingScope */
2023-07-20 05:58:46 +00:00
$mutatingScope = $this -> resolveClassOrInterfaceScope ( $node , $mutatingScope );
2021-03-18 01:48:44 +00:00
}
2019-10-02 20:13:37 +00:00
// special case for unreachable nodes
2022-06-07 08:22:29 +00:00
if ( $node instanceof UnreachableStatementNode ) {
2022-09-01 09:30:44 +00:00
$this -> processUnreachableStatementNode ( $node , $filePath , $mutatingScope );
2019-10-02 20:13:37 +00:00
} else {
2022-06-07 08:22:29 +00:00
$node -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2019-10-02 20:13:37 +00:00
}
2020-09-16 18:11:35 +00:00
};
2024-02-08 07:30:40 +00:00
$this -> nodeScopeResolverProcessNodes ( $stmts , $scope , $nodeCallback );
2023-08-19 14:25:13 +00:00
$nodeTraverser = new NodeTraverser ();
$nodeTraverser -> addVisitor ( new WrappedNodeRestoringNodeVisitor ());
2023-09-28 13:11:33 +00:00
$nodeTraverser -> addVisitor ( new ExprScopeFromStmtNodeVisitor ( $this , $filePath , $scope ));
2023-08-19 14:25:13 +00:00
$nodeTraverser -> traverse ( $stmts );
return $stmts ;
2021-08-16 08:19:28 +00:00
}
2024-02-11 00:29:29 +00:00
public function hasUnreachableStatementNode () : bool
{
return $this -> hasUnreachableStatementNode ;
}
public function resetHasUnreachableStatementNode () : void
{
$this -> hasUnreachableStatementNode = \false ;
}
2024-02-08 07:30:40 +00:00
/**
* @ param Stmt [] $stmts
* @ param callable ( Node $node , MutatingScope $scope ) : void $nodeCallback
*/
private function nodeScopeResolverProcessNodes ( array $stmts , MutatingScope $mutatingScope , callable $nodeCallback ) : void
{
try {
$this -> nodeScopeResolver -> processNodes ( $stmts , $mutatingScope , $nodeCallback );
} catch ( Throwable $throwable ) {
if ( $throwable -> getMessage () !== 'Internal error.' ) {
throw $throwable ;
}
}
}
2023-06-17 06:21:36 +00:00
private function processCallike ( CallLike $callLike , MutatingScope $mutatingScope ) : void
{
if ( $callLike instanceof StaticCall ) {
$callLike -> class -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
$callLike -> name -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-13 00:07:19 +00:00
} elseif ( $callLike instanceof MethodCall || $callLike instanceof NullsafeMethodCall ) {
2023-06-17 06:21:36 +00:00
$callLike -> var -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
$callLike -> name -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-12 23:39:23 +00:00
} elseif ( $callLike instanceof FuncCall ) {
2023-06-17 06:21:36 +00:00
$callLike -> name -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-08-12 23:39:23 +00:00
} elseif ( $callLike instanceof New_ && ! $callLike -> class instanceof Class_ ) {
2023-06-17 06:21:36 +00:00
$callLike -> class -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
}
2023-06-14 14:21:17 +00:00
/**
* @ param \PhpParser\Node\Expr\Assign | \PhpParser\Node\Expr\AssignOp $assign
*/
private function processAssign ( $assign , MutatingScope $mutatingScope ) : void
{
2023-07-01 23:02:38 +00:00
$assign -> var -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
$assign -> expr -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2023-06-14 14:21:17 +00:00
}
2022-11-16 14:19:15 +00:00
private function processArray ( Array_ $array , MutatingScope $mutatingScope ) : void
{
foreach ( $array -> items as $arrayItem ) {
if ( $arrayItem instanceof ArrayItem ) {
2024-04-05 22:38:12 +00:00
$this -> processArrayItem ( $arrayItem , $mutatingScope );
2022-11-16 14:19:15 +00:00
}
}
}
2022-07-27 08:02:59 +00:00
private function processArrayItem ( ArrayItem $arrayItem , MutatingScope $mutatingScope ) : void
{
if ( $arrayItem -> key instanceof Expr ) {
$arrayItem -> key -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
$arrayItem -> value -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
2022-07-18 14:32:34 +00:00
private function decorateTraitAttrGroups ( Trait_ $trait , MutatingScope $mutatingScope ) : void
{
foreach ( $trait -> attrGroups as $attrGroup ) {
foreach ( $attrGroup -> attrs as $attr ) {
foreach ( $attr -> args as $arg ) {
$arg -> value -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
}
}
}
private function processSwitch ( Switch_ $switch , MutatingScope $mutatingScope ) : void
{
// decorate value as well
foreach ( $switch -> cases as $case ) {
$case -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
}
2023-10-27 13:02:33 +00:00
private function processCatch ( Catch_ $catch , string $filePath , MutatingScope $mutatingScope ) : void
{
$varName = $catch -> var instanceof Variable ? $this -> nodeNameResolver -> getName ( $catch -> var ) : null ;
$type = TypeCombinator :: union ( ... \array_map ( static function ( Name $name ) : ObjectType {
return new ObjectType (( string ) $name );
}, $catch -> types ));
$catchMutatingScope = $mutatingScope -> enterCatchType ( $type , $varName );
$this -> processNodes ( $catch -> stmts , $filePath , $catchMutatingScope );
}
2023-10-27 17:46:00 +00:00
private function processTryCatch ( TryCatch $tryCatch , MutatingScope $mutatingScope ) : void
2022-07-18 14:32:34 +00:00
{
if ( $tryCatch -> finally instanceof Finally_ ) {
$tryCatch -> finally -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
}
2022-09-01 09:30:44 +00:00
private function processUnreachableStatementNode ( UnreachableStatementNode $unreachableStatementNode , string $filePath , MutatingScope $mutatingScope ) : void
2022-06-19 08:24:30 +00:00
{
$originalStmt = $unreachableStatementNode -> getOriginalStatement ();
$originalStmt -> setAttribute ( AttributeKey :: IS_UNREACHABLE , \true );
$originalStmt -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
2022-09-01 09:30:44 +00:00
$this -> processNodes ([ $originalStmt ], $filePath , $mutatingScope );
2023-07-04 13:33:50 +00:00
$this -> hasUnreachableStatementNode = \true ;
}
2022-06-19 08:24:30 +00:00
private function processProperty ( Property $property , MutatingScope $mutatingScope ) : void
{
foreach ( $property -> props as $propertyProperty ) {
$propertyProperty -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
if ( $propertyProperty -> default instanceof Expr ) {
$propertyProperty -> default -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
}
foreach ( $property -> attrGroups as $attrGroup ) {
foreach ( $attrGroup -> attrs as $attribute ) {
$attribute -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
}
}
private function processBinaryOp ( BinaryOp $binaryOp , MutatingScope $mutatingScope ) : void
{
$binaryOp -> left -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
$binaryOp -> right -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
private function processTernary ( Ternary $ternary , MutatingScope $mutatingScope ) : void
{
if ( $ternary -> if instanceof Expr ) {
$ternary -> if -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
$ternary -> else -> setAttribute ( AttributeKey :: SCOPE , $mutatingScope );
}
2018-08-10 15:17:09 +00:00
/**
2022-05-12 09:11:03 +00:00
* @ param \PhpParser\Node\Stmt\Class_ | \PhpParser\Node\Stmt\Interface_ | \PhpParser\Node\Stmt\Enum_ $classLike
2018-08-10 15:17:09 +00:00
*/
2023-07-20 05:58:46 +00:00
private function resolveClassOrInterfaceScope ( $classLike , MutatingScope $mutatingScope ) : MutatingScope
2020-08-27 10:19:22 +00:00
{
2020-07-26 09:00:23 +00:00
$className = $this -> resolveClassName ( $classLike );
2023-05-09 19:13:23 +00:00
$isAnonymous = $this -> classAnalyzer -> isAnonymousClass ( $classLike );
2020-07-26 09:00:23 +00:00
// is anonymous class? - not possible to enter it since PHPStan 0.12.33, see https://github.com/phpstan/phpstan-src/commit/e87fb0ec26f9c8552bbeef26a868b1e5d8185e91
2023-05-09 19:13:23 +00:00
if ( $classLike instanceof Class_ && $isAnonymous ) {
2021-10-04 21:24:17 +00:00
$classReflection = $this -> reflectionProvider -> getAnonymousClassReflection ( $classLike , $mutatingScope );
2021-05-09 20:15:43 +00:00
} elseif ( ! $this -> reflectionProvider -> hasClass ( $className )) {
2021-10-04 21:24:17 +00:00
return $mutatingScope ;
2021-03-18 01:48:44 +00:00
} else {
$classReflection = $this -> reflectionProvider -> getClass ( $className );
2020-07-26 09:00:23 +00:00
}
2023-07-20 05:58:46 +00:00
try {
return $mutatingScope -> enterClass ( $classReflection );
} catch ( \PHPStan\ShouldNotHappenException $exception ) {
2022-05-12 09:11:03 +00:00
}
2023-07-20 23:57:52 +00:00
$context = $this -> privatesAccessor -> getPrivateProperty ( $mutatingScope , 'context' );
$this -> privatesAccessor -> setPrivateProperty ( $context , 'classReflection' , null );
2021-10-04 21:24:17 +00:00
return $mutatingScope -> enterClass ( $classReflection );
2019-03-10 23:47:43 +00:00
}
/**
2022-05-12 09:11:03 +00:00
* @ param \PhpParser\Node\Stmt\Class_ | \PhpParser\Node\Stmt\Interface_ | \PhpParser\Node\Stmt\Trait_ | \PhpParser\Node\Stmt\Enum_ $classLike
2019-03-10 23:47:43 +00:00
*/
2021-05-30 10:12:56 +00:00
private function resolveClassName ( $classLike ) : string
2018-08-10 15:17:09 +00:00
{
2022-06-07 08:22:29 +00:00
if ( $classLike -> namespacedName instanceof Name ) {
2020-02-07 07:46:29 +00:00
return ( string ) $classLike -> namespacedName ;
2018-08-10 15:17:09 +00:00
}
2023-03-23 23:21:34 +00:00
if ( ! $classLike -> name instanceof Identifier ) {
2022-06-07 08:22:29 +00:00
throw new ShouldNotHappenException ();
2018-08-10 15:17:09 +00:00
}
2020-02-07 07:46:29 +00:00
return $classLike -> name -> toString ();
2018-08-10 15:17:09 +00:00
}
2023-08-14 09:58:25 +00:00
/**
2023-08-14 10:12:37 +00:00
* @ param callable ( Node $trait , MutatingScope $scope ) : void $nodeCallback
2023-08-14 09:58:25 +00:00
*/
2023-08-14 10:12:37 +00:00
private function processTrait ( Trait_ $trait , MutatingScope $mutatingScope , callable $nodeCallback ) : void
2023-08-14 09:58:25 +00:00
{
2023-08-14 10:12:37 +00:00
$traitName = $this -> resolveClassName ( $trait );
2023-08-14 09:58:25 +00:00
$traitClassReflection = $this -> reflectionProvider -> getClass ( $traitName );
$traitScope = clone $mutatingScope ;
/** @var ScopeContext $scopeContext */
$scopeContext = $this -> privatesAccessor -> getPrivateProperty ( $traitScope , self :: CONTEXT );
$traitContext = clone $scopeContext ;
// before entering the class/trait again, we have to tell scope no class was set, otherwise it crashes
$this -> privatesAccessor -> setPrivateProperty ( $traitContext , 'classReflection' , $traitClassReflection );
$this -> privatesAccessor -> setPrivateProperty ( $traitScope , self :: CONTEXT , $traitContext );
2023-08-14 10:12:37 +00:00
$trait -> setAttribute ( AttributeKey :: SCOPE , $traitScope );
2024-02-08 07:30:40 +00:00
$this -> nodeScopeResolverProcessNodes ( $trait -> stmts , $traitScope , $nodeCallback );
2023-08-14 10:12:37 +00:00
$this -> decorateTraitAttrGroups ( $trait , $traitScope );
2023-08-14 09:58:25 +00:00
}
2018-08-03 18:41:30 +00:00
}