Skip to content

Commit 2a61ebc

Browse files
herndlmondrejmirtes
authored andcommitted
Refactor FilterVarDynamicReturnTypeExtension to pass around Types instead of Args and the Scope
1 parent 901d789 commit 2a61ebc

File tree

1 file changed

+24
-28
lines changed

1 file changed

+24
-28
lines changed

src/Type/Php/FilterVarDynamicReturnTypeExtension.php

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace PHPStan\Type\Php;
44

55
use PhpParser\Node;
6-
use PhpParser\Node\Arg;
76
use PhpParser\Node\Expr\FuncCall;
87
use PHPStan\Analyser\Scope;
98
use PHPStan\Reflection\FunctionReflection;
@@ -143,32 +142,30 @@ public function getTypeFromFunctionCall(
143142
{
144143
$mixedType = new MixedType();
145144

146-
$filterArg = $functionCall->getArgs()[1] ?? null;
147-
if ($filterArg === null) {
145+
$filterType = isset($functionCall->getArgs()[1]) ? $scope->getType($functionCall->getArgs()[1]->value) : null;
146+
if ($filterType === null) {
148147
$filterValue = $this->getConstant('FILTER_DEFAULT');
149148
} else {
150-
$filterType = $scope->getType($filterArg->value);
151149
if (!$filterType instanceof ConstantIntegerType) {
152150
return $mixedType;
153151
}
154152
$filterValue = $filterType->getValue();
155153
}
156154

157-
$flagsArg = $functionCall->getArgs()[2] ?? null;
155+
$flagsType = isset($functionCall->getArgs()[2]) ? $scope->getType($functionCall->getArgs()[2]->value) : null;
158156
$inputType = $scope->getType($functionCall->getArgs()[0]->value);
159-
160-
$defaultType = $this->hasFlag($this->getConstant('FILTER_NULL_ON_FAILURE'), $flagsArg, $scope)
157+
$defaultType = $this->hasFlag($this->getConstant('FILTER_NULL_ON_FAILURE'), $flagsType)
161158
? new NullType()
162159
: new ConstantBooleanType(false);
163-
$exactType = $this->determineExactType($inputType, $filterValue, $defaultType, $flagsArg, $scope);
160+
$exactType = $this->determineExactType($inputType, $filterValue, $defaultType, $flagsType);
164161
$type = $exactType ?? $this->getFilterTypeMap()[$filterValue] ?? $mixedType;
165162

166163
$typeOptionNames = $this->getFilterTypeOptions()[$filterValue] ?? [];
167-
$otherTypes = $this->getOtherTypes($flagsArg, $scope, $typeOptionNames, $defaultType);
164+
$otherTypes = $this->getOtherTypes($flagsType, $typeOptionNames, $defaultType);
168165

169166
if ($inputType->isNonEmptyString()->yes()
170167
&& $type->isString()->yes()
171-
&& !$this->canStringBeSanitized($filterValue, $flagsArg, $scope)) {
168+
&& !$this->canStringBeSanitized($filterValue, $flagsType)) {
172169
$accessory = new AccessoryNonEmptyStringType();
173170
if ($inputType->isNonFalsyString()->yes()) {
174171
$accessory = new AccessoryNonFalsyStringType();
@@ -196,14 +193,14 @@ public function getTypeFromFunctionCall(
196193
$type = TypeCombinator::union($type, $otherTypes['default']);
197194
}
198195

199-
if ($this->hasFlag($this->getConstant('FILTER_FORCE_ARRAY'), $flagsArg, $scope)) {
196+
if ($this->hasFlag($this->getConstant('FILTER_FORCE_ARRAY'), $flagsType)) {
200197
return new ArrayType(new MixedType(), $type);
201198
}
202199

203200
return $type;
204201
}
205202

206-
private function determineExactType(Type $in, int $filterValue, Type $defaultType, ?Arg $flagsArg, Scope $scope): ?Type
203+
private function determineExactType(Type $in, int $filterValue, Type $defaultType, ?Type $flagsType): ?Type
207204
{
208205
if (($filterValue === $this->getConstant('FILTER_VALIDATE_BOOLEAN') && $in->isBoolean()->yes())
209206
|| ($filterValue === $this->getConstant('FILTER_VALIDATE_INT') && $in->isInteger()->yes())
@@ -213,8 +210,8 @@ private function determineExactType(Type $in, int $filterValue, Type $defaultTyp
213210

214211
if ($filterValue === $this->getConstant('FILTER_VALIDATE_INT') && $in instanceof ConstantStringType) {
215212
$value = $in->getValue();
216-
$allowOctal = $this->hasFlag($this->getConstant('FILTER_FLAG_ALLOW_OCTAL'), $flagsArg, $scope);
217-
$allowHex = $this->hasFlag($this->getConstant('FILTER_FLAG_ALLOW_HEX'), $flagsArg, $scope);
213+
$allowOctal = $this->hasFlag($this->getConstant('FILTER_FLAG_ALLOW_OCTAL'), $flagsType);
214+
$allowHex = $this->hasFlag($this->getConstant('FILTER_FLAG_ALLOW_HEX'), $flagsType);
218215

219216
if ($allowOctal && preg_match('/\A0[oO][0-7]+\z/', $value) === 1) {
220217
$octalValue = octdec($value);
@@ -240,14 +237,14 @@ private function determineExactType(Type $in, int $filterValue, Type $defaultTyp
240237
* @param list<string> $typeOptionNames
241238
* @return array{default: Type, range?: Type}
242239
*/
243-
private function getOtherTypes(?Node\Arg $flagsArg, Scope $scope, array $typeOptionNames, Type $defaultType): array
240+
private function getOtherTypes(?Type $flagsType, array $typeOptionNames, Type $defaultType): array
244241
{
245242
$falseType = new ConstantBooleanType(false);
246-
if ($flagsArg === null) {
243+
if ($flagsType === null) {
247244
return ['default' => $falseType];
248245
}
249246

250-
$typeOptions = $this->getOptions($flagsArg, $scope, 'default', ...$typeOptionNames);
247+
$typeOptions = $this->getOptions($flagsType, 'default', ...$typeOptionNames);
251248
$defaultType = $typeOptions['default'] ?? $defaultType;
252249
$otherTypes = ['default' => $defaultType];
253250
$range = [];
@@ -278,16 +275,15 @@ private function getOtherTypes(?Node\Arg $flagsArg, Scope $scope, array $typeOpt
278275
/**
279276
* @return array<string, ?Type>
280277
*/
281-
private function getOptions(Node\Arg $expression, Scope $scope, string ...$optionNames): array
278+
private function getOptions(Type $flagsType, string ...$optionNames): array
282279
{
283280
$options = [];
284281

285-
$exprType = $scope->getType($expression->value);
286-
if (!$exprType instanceof ConstantArrayType) {
282+
if (!$flagsType instanceof ConstantArrayType) {
287283
return $options;
288284
}
289285

290-
$optionsType = $exprType->getOffsetValueType(new ConstantStringType('options'));
286+
$optionsType = $flagsType->getOffsetValueType(new ConstantStringType('options'));
291287
if (!$optionsType instanceof ConstantArrayType) {
292288
return $options;
293289
}
@@ -300,13 +296,13 @@ private function getOptions(Node\Arg $expression, Scope $scope, string ...$optio
300296
return $options;
301297
}
302298

303-
private function hasFlag(int $flag, ?Node\Arg $expression, Scope $scope): bool
299+
private function hasFlag(int $flag, ?Type $flagsType): bool
304300
{
305-
if ($expression === null) {
301+
if ($flagsType === null) {
306302
return false;
307303
}
308304

309-
$type = $this->getFlagsValue($scope->getType($expression->value));
305+
$type = $this->getFlagsValue($flagsType);
310306

311307
return $type instanceof ConstantIntegerType && ($type->getValue() & $flag) === $flag;
312308
}
@@ -320,7 +316,7 @@ private function getFlagsValue(Type $exprType): Type
320316
return $exprType->getOffsetValueType($this->flagsString);
321317
}
322318

323-
private function canStringBeSanitized(int $filterValue, ?Node\Arg $flagsArg, Scope $scope): bool
319+
private function canStringBeSanitized(int $filterValue, ?Type $flagsType): bool
324320
{
325321
// If it is a validation filter, the string will not be changed
326322
if (($filterValue & self::VALIDATION_FILTER_BITMASK) !== 0) {
@@ -330,9 +326,9 @@ private function canStringBeSanitized(int $filterValue, ?Node\Arg $flagsArg, Sco
330326
// FILTER_DEFAULT will not sanitize, unless it has FILTER_FLAG_STRIP_LOW,
331327
// FILTER_FLAG_STRIP_HIGH, or FILTER_FLAG_STRIP_BACKTICK
332328
if ($filterValue === $this->getConstant('FILTER_DEFAULT')) {
333-
return $this->hasFlag($this->getConstant('FILTER_FLAG_STRIP_LOW'), $flagsArg, $scope)
334-
|| $this->hasFlag($this->getConstant('FILTER_FLAG_STRIP_HIGH'), $flagsArg, $scope)
335-
|| $this->hasFlag($this->getConstant('FILTER_FLAG_STRIP_BACKTICK'), $flagsArg, $scope);
329+
return $this->hasFlag($this->getConstant('FILTER_FLAG_STRIP_LOW'), $flagsType)
330+
|| $this->hasFlag($this->getConstant('FILTER_FLAG_STRIP_HIGH'), $flagsType)
331+
|| $this->hasFlag($this->getConstant('FILTER_FLAG_STRIP_BACKTICK'), $flagsType);
336332
}
337333

338334
return true;

0 commit comments

Comments
 (0)