|
2 | 2 |
|
3 | 3 | namespace PHPStan\Type\Php; |
4 | 4 |
|
5 | | -use Closure; |
6 | 5 | use PhpParser\Node\Arg; |
7 | 6 | use PhpParser\Node\Expr\FuncCall; |
8 | 7 | use PHPStan\Analyser\Scope; |
@@ -73,34 +72,17 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, |
73 | 72 | return $noArgsReturnType; |
74 | 73 | } |
75 | 74 |
|
76 | | - $argType = $scope->getType($args[0]->value); |
77 | | - $functionName = $functionReflection->getName(); |
78 | | - $proc = $this->getProc($functionName, $args, $scope); |
79 | | - |
80 | | - if ($proc !== null) { |
81 | | - $constantScalarValues = $argType->getConstantScalarValues(); |
82 | | - $returnValueTypes = []; |
83 | | - |
84 | | - foreach ($constantScalarValues as $constantScalarValue) { |
85 | | - if (!is_int($constantScalarValue) && !is_float($constantScalarValue)) { |
86 | | - $returnValueTypes = []; |
87 | | - break; |
88 | | - } |
89 | | - |
90 | | - $returnValueTypes[] = new ConstantFloatType($proc($constantScalarValue)); |
91 | | - } |
92 | | - |
93 | | - if (count($returnValueTypes) >= 1) { |
94 | | - return TypeCombinator::union(...array_map(static fn ($l) => $l, $returnValueTypes)); |
95 | | - } |
96 | | - } |
97 | | - |
98 | | - $firstArgType = $scope->getType($functionCall->getArgs()[0]->value); |
99 | | - |
| 75 | + $firstArgType = $scope->getType($args[0]->value); |
100 | 76 | if ($firstArgType instanceof MixedType) { |
101 | 77 | return $defaultReturnType; |
102 | 78 | } |
103 | 79 |
|
| 80 | + $functionName = $functionReflection->getName(); |
| 81 | + $returnConstantType = $this->resolveConstantType($functionName, $args, $scope, $firstArgType); |
| 82 | + if ($returnConstantType !== null) { |
| 83 | + return $returnConstantType; |
| 84 | + } |
| 85 | + |
104 | 86 | if ($this->phpVersion->hasStricterRoundFunctions()) { |
105 | 87 | <<<<<<< HEAD |
106 | 88 | ======= |
@@ -144,46 +126,64 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, |
144 | 126 | /** |
145 | 127 | * @param Arg[] $args |
146 | 128 | */ |
147 | | - public function getProc(string $functionName, array $args, Scope $scope): ?Closure |
| 129 | + public function resolveConstantType(string $functionName, array $args, Scope $scope, Type $argType): ?Type |
148 | 130 | { |
| 131 | + $proc = null; |
| 132 | + |
149 | 133 | if ($functionName === 'floor') { |
150 | | - return static fn ($name) => floor($name); |
151 | | - } |
| 134 | + $proc = static fn ($name) => floor($name); |
| 135 | + } elseif ($functionName === 'ceil') { |
| 136 | + $proc = static fn ($name) => ceil($name); |
| 137 | + } elseif ($functionName === 'round') { |
| 138 | + if (count($args) === 1) { |
| 139 | + $proc = static fn ($name) => round($name); |
| 140 | + } else { |
| 141 | + if (isset($args[1]->value)) { |
| 142 | + $precisionArg = $args[1]->value; |
| 143 | + $precisionType = $scope->getType($precisionArg); |
| 144 | + $precisions = $precisionType->getConstantScalarValues(); |
| 145 | + if (count($precisions) !== 1 || !is_int($precisions[0])) { |
| 146 | + return null; |
| 147 | + } |
| 148 | + $precision = $precisions[0]; |
| 149 | + } else { |
| 150 | + $precision = 0; |
| 151 | + } |
152 | 152 |
|
153 | | - if ($functionName === 'ceil') { |
154 | | - return static fn ($name) => ceil($name); |
155 | | - } |
| 153 | + if (!isset($args[2]->value)) { |
| 154 | + $proc = static fn ($name) => round($name, $precision); |
| 155 | + } else { |
| 156 | + $modeArg = $args[2]->value; |
| 157 | + $modeType = $scope->getType($modeArg); |
| 158 | + $mode = $modeType->getConstantScalarValues(); |
156 | 159 |
|
157 | | - if ($functionName === 'round') { |
158 | | - if (count($args) === 1) { |
159 | | - return static fn ($name) => round($name); |
160 | | - } |
161 | | - if (isset($args[1]->value)) { |
162 | | - $precisionArg = $args[1]->value; |
163 | | - $precisionType = $scope->getType($precisionArg); |
164 | | - $precisions = $precisionType->getConstantScalarValues(); |
165 | | - if (count($precisions) !== 1 || !is_int($precisions[0])) { |
166 | | - return null; |
| 160 | + if (count($mode) === 1 && is_int($mode[0])) { |
| 161 | + $proc = static fn ($name) => round($name, $precision, $mode[0]); |
| 162 | + } |
167 | 163 | } |
168 | | - $precision = $precisions[0]; |
169 | | - } else { |
170 | | - $precision = 0; |
171 | 164 | } |
| 165 | + } |
172 | 166 |
|
173 | | - if (!isset($args[2]->value)) { |
174 | | - return static fn ($name) => round($name, $precision); |
175 | | - } |
| 167 | + if ($proc === null) { |
| 168 | + return null; |
| 169 | + } |
176 | 170 |
|
177 | | - $modeArg = $args[2]->value; |
178 | | - $modeType = $scope->getType($modeArg); |
179 | | - $mode = $modeType->getConstantScalarValues(); |
| 171 | + $constantScalarValues = $argType->getConstantScalarValues(); |
| 172 | + $returnValueTypes = []; |
180 | 173 |
|
181 | | - if (count($mode) === 1 && is_int($mode[0])) { |
182 | | - return static fn ($name) => round($name, $precision, $mode[0]); |
| 174 | + foreach ($constantScalarValues as $constantScalarValue) { |
| 175 | + if (!is_int($constantScalarValue) && !is_float($constantScalarValue)) { |
| 176 | + $returnValueTypes = []; |
| 177 | + break; |
183 | 178 | } |
| 179 | + |
| 180 | + $returnValueTypes[] = new ConstantFloatType($proc($constantScalarValue)); |
| 181 | + } |
| 182 | + |
| 183 | + if (count($returnValueTypes) >= 1) { |
| 184 | + return TypeCombinator::union(...array_map(static fn ($l) => $l, $returnValueTypes)); |
184 | 185 | } |
185 | 186 |
|
186 | 187 | return null; |
187 | 188 | } |
188 | | - |
189 | 189 | } |
0 commit comments