20
20
use PHPStan \PhpDocParser \Ast \ConstExpr \ConstExprStringNode ;
21
21
use PHPStan \PhpDocParser \Ast \ConstExpr \ConstExprTrueNode ;
22
22
use PHPStan \PhpDocParser \Ast \ConstExpr \ConstFetchNode ;
23
+ use PHPStan \PhpDocParser \Ast \Type \ArrayShapeItemNode ;
23
24
use PHPStan \PhpDocParser \Ast \Type \ArrayShapeNode ;
24
25
use PHPStan \PhpDocParser \Ast \Type \ArrayTypeNode ;
25
26
use PHPStan \PhpDocParser \Ast \Type \CallableTypeNode ;
@@ -1050,16 +1051,7 @@ private function resolveArrayShapeNode(ArrayShapeNode $typeNode, NameScope $name
1050
1051
}
1051
1052
1052
1053
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 );
1063
1055
$ builder ->setOffsetValueType ($ offsetType , $ this ->resolve ($ itemNode ->valueType , $ nameScope ), $ itemNode ->optional );
1064
1056
}
1065
1057
@@ -1081,6 +1073,69 @@ private function resolveArrayShapeNode(ArrayShapeNode $typeNode, NameScope $name
1081
1073
return $ arrayType ;
1082
1074
}
1083
1075
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
+
1084
1139
private function resolveObjectShapeNode (ObjectShapeNode $ typeNode , NameScope $ nameScope ): Type
1085
1140
{
1086
1141
$ properties = [];
0 commit comments