2020use PHPStan \PhpDocParser \Ast \ConstExpr \ConstExprStringNode ;
2121use PHPStan \PhpDocParser \Ast \ConstExpr \ConstExprTrueNode ;
2222use PHPStan \PhpDocParser \Ast \ConstExpr \ConstFetchNode ;
23+ use PHPStan \PhpDocParser \Ast \Type \ArrayShapeItemNode ;
2324use PHPStan \PhpDocParser \Ast \Type \ArrayShapeNode ;
2425use PHPStan \PhpDocParser \Ast \Type \ArrayTypeNode ;
2526use PHPStan \PhpDocParser \Ast \Type \CallableTypeNode ;
@@ -1050,16 +1051,7 @@ private function resolveArrayShapeNode(ArrayShapeNode $typeNode, NameScope $name
10501051 }
10511052
10521053 foreach ($ typeNode ->items as $ itemNode ) {
1053- $ offsetType = null ;
1054- if ($ itemNode ->keyName instanceof ConstExprIntegerNode) {
1055- $ offsetType = new ConstantIntegerType ((int ) $ itemNode ->keyName ->value );
1056- } elseif ($ itemNode ->keyName instanceof IdentifierTypeNode) {
1057- $ offsetType = new ConstantStringType ($ itemNode ->keyName ->name );
1058- } elseif ($ itemNode ->keyName instanceof ConstExprStringNode) {
1059- $ offsetType = new ConstantStringType ($ itemNode ->keyName ->value );
1060- } elseif ($ itemNode ->keyName !== null ) {
1061- throw new ShouldNotHappenException ('Unsupported key node type: ' . get_class ($ itemNode ->keyName ));
1062- }
1054+ $ offsetType = $ this ->resolveArrayShapeOffsetType ($ itemNode , $ nameScope );
10631055 $ builder ->setOffsetValueType ($ offsetType , $ this ->resolve ($ itemNode ->valueType , $ nameScope ), $ itemNode ->optional );
10641056 }
10651057
@@ -1081,6 +1073,69 @@ private function resolveArrayShapeNode(ArrayShapeNode $typeNode, NameScope $name
10811073 return $ arrayType ;
10821074 }
10831075
1076+ private function resolveArrayShapeOffsetType (ArrayShapeItemNode $ itemNode , NameScope $ nameScope ): ?Type
1077+ {
1078+ if ($ itemNode ->keyName instanceof ConstExprIntegerNode) {
1079+ return new ConstantIntegerType ((int ) $ itemNode ->keyName ->value );
1080+ } elseif ($ itemNode ->keyName instanceof IdentifierTypeNode) {
1081+ return new ConstantStringType ($ itemNode ->keyName ->name );
1082+ } elseif ($ itemNode ->keyName instanceof ConstExprStringNode) {
1083+ return new ConstantStringType ($ itemNode ->keyName ->value );
1084+ } elseif ($ itemNode ->keyName instanceof ConstFetchNode) {
1085+ $ constExpr = $ itemNode ->keyName ;
1086+ if ($ constExpr ->className === '' ) {
1087+ throw new ShouldNotHappenException (); // global constant should get parsed as class name in IdentifierTypeNode
1088+ }
1089+
1090+ if ($ nameScope ->getClassName () !== null ) {
1091+ switch (strtolower ($ constExpr ->className )) {
1092+ case 'static ' :
1093+ case 'self ' :
1094+ $ className = $ nameScope ->getClassName ();
1095+ break ;
1096+
1097+ case 'parent ' :
1098+ if ($ this ->getReflectionProvider ()->hasClass ($ nameScope ->getClassName ())) {
1099+ $ classReflection = $ this ->getReflectionProvider ()->getClass ($ nameScope ->getClassName ());
1100+ if ($ classReflection ->getParentClass () === null ) {
1101+ return new ErrorType ();
1102+
1103+ }
1104+
1105+ $ className = $ classReflection ->getParentClass ()->getName ();
1106+ }
1107+ break ;
1108+ }
1109+ }
1110+
1111+ if (!isset ($ className )) {
1112+ $ className = $ nameScope ->resolveStringName ($ constExpr ->className );
1113+ }
1114+
1115+ if (!$ this ->getReflectionProvider ()->hasClass ($ className )) {
1116+ return new ErrorType ();
1117+ }
1118+ $ classReflection = $ this ->getReflectionProvider ()->getClass ($ className );
1119+
1120+ $ constantName = $ constExpr ->name ;
1121+ if (!$ classReflection ->hasConstant ($ constantName )) {
1122+ return new ErrorType ();
1123+ }
1124+
1125+ $ reflectionConstant = $ classReflection ->getNativeReflection ()->getReflectionConstant ($ constantName );
1126+ if ($ reflectionConstant === false ) {
1127+ return new ErrorType ();
1128+ }
1129+ $ declaringClass = $ reflectionConstant ->getDeclaringClass ();
1130+
1131+ return $ this ->initializerExprTypeResolver ->getType ($ reflectionConstant ->getValueExpression (), InitializerExprContext::fromClass ($ declaringClass ->getName (), $ declaringClass ->getFileName () ?: null ));
1132+ } elseif ($ itemNode ->keyName !== null ) {
1133+ throw new ShouldNotHappenException ('Unsupported key node type: ' . get_class ($ itemNode ->keyName ));
1134+ }
1135+
1136+ return null ;
1137+ }
1138+
10841139 private function resolveObjectShapeNode (ObjectShapeNode $ typeNode , NameScope $ nameScope ): Type
10851140 {
10861141 $ properties = [];
0 commit comments