3
3
namespace PHPStan \Type \Php ;
4
4
5
5
use PhpParser \Node ;
6
- use PhpParser \Node \Arg ;
7
6
use PhpParser \Node \Expr \FuncCall ;
8
7
use PHPStan \Analyser \Scope ;
9
8
use PHPStan \Reflection \FunctionReflection ;
@@ -143,32 +142,30 @@ public function getTypeFromFunctionCall(
143
142
{
144
143
$ mixedType = new MixedType ();
145
144
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 ) {
148
147
$ filterValue = $ this ->getConstant ('FILTER_DEFAULT ' );
149
148
} else {
150
- $ filterType = $ scope ->getType ($ filterArg ->value );
151
149
if (!$ filterType instanceof ConstantIntegerType) {
152
150
return $ mixedType ;
153
151
}
154
152
$ filterValue = $ filterType ->getValue ();
155
153
}
156
154
157
- $ flagsArg = $ functionCall ->getArgs ()[2 ] ?? null ;
155
+ $ flagsType = isset ( $ functionCall ->getArgs ()[2 ]) ? $ scope -> getType ( $ functionCall -> getArgs ()[ 2 ]-> value ) : null ;
158
156
$ 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 )
161
158
? new NullType ()
162
159
: new ConstantBooleanType (false );
163
- $ exactType = $ this ->determineExactType ($ inputType , $ filterValue , $ defaultType , $ flagsArg , $ scope );
160
+ $ exactType = $ this ->determineExactType ($ inputType , $ filterValue , $ defaultType , $ flagsType );
164
161
$ type = $ exactType ?? $ this ->getFilterTypeMap ()[$ filterValue ] ?? $ mixedType ;
165
162
166
163
$ typeOptionNames = $ this ->getFilterTypeOptions ()[$ filterValue ] ?? [];
167
- $ otherTypes = $ this ->getOtherTypes ($ flagsArg , $ scope , $ typeOptionNames , $ defaultType );
164
+ $ otherTypes = $ this ->getOtherTypes ($ flagsType , $ typeOptionNames , $ defaultType );
168
165
169
166
if ($ inputType ->isNonEmptyString ()->yes ()
170
167
&& $ type ->isString ()->yes ()
171
- && !$ this ->canStringBeSanitized ($ filterValue , $ flagsArg , $ scope )) {
168
+ && !$ this ->canStringBeSanitized ($ filterValue , $ flagsType )) {
172
169
$ accessory = new AccessoryNonEmptyStringType ();
173
170
if ($ inputType ->isNonFalsyString ()->yes ()) {
174
171
$ accessory = new AccessoryNonFalsyStringType ();
@@ -196,14 +193,14 @@ public function getTypeFromFunctionCall(
196
193
$ type = TypeCombinator::union ($ type , $ otherTypes ['default ' ]);
197
194
}
198
195
199
- if ($ this ->hasFlag ($ this ->getConstant ('FILTER_FORCE_ARRAY ' ), $ flagsArg , $ scope )) {
196
+ if ($ this ->hasFlag ($ this ->getConstant ('FILTER_FORCE_ARRAY ' ), $ flagsType )) {
200
197
return new ArrayType (new MixedType (), $ type );
201
198
}
202
199
203
200
return $ type ;
204
201
}
205
202
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
207
204
{
208
205
if (($ filterValue === $ this ->getConstant ('FILTER_VALIDATE_BOOLEAN ' ) && $ in ->isBoolean ()->yes ())
209
206
|| ($ filterValue === $ this ->getConstant ('FILTER_VALIDATE_INT ' ) && $ in ->isInteger ()->yes ())
@@ -213,8 +210,8 @@ private function determineExactType(Type $in, int $filterValue, Type $defaultTyp
213
210
214
211
if ($ filterValue === $ this ->getConstant ('FILTER_VALIDATE_INT ' ) && $ in instanceof ConstantStringType) {
215
212
$ 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 );
218
215
219
216
if ($ allowOctal && preg_match ('/\A0[oO][0-7]+\z/ ' , $ value ) === 1 ) {
220
217
$ octalValue = octdec ($ value );
@@ -240,14 +237,14 @@ private function determineExactType(Type $in, int $filterValue, Type $defaultTyp
240
237
* @param list<string> $typeOptionNames
241
238
* @return array{default: Type, range?: Type}
242
239
*/
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
244
241
{
245
242
$ falseType = new ConstantBooleanType (false );
246
- if ($ flagsArg === null ) {
243
+ if ($ flagsType === null ) {
247
244
return ['default ' => $ falseType ];
248
245
}
249
246
250
- $ typeOptions = $ this ->getOptions ($ flagsArg , $ scope , 'default ' , ...$ typeOptionNames );
247
+ $ typeOptions = $ this ->getOptions ($ flagsType , 'default ' , ...$ typeOptionNames );
251
248
$ defaultType = $ typeOptions ['default ' ] ?? $ defaultType ;
252
249
$ otherTypes = ['default ' => $ defaultType ];
253
250
$ range = [];
@@ -278,16 +275,15 @@ private function getOtherTypes(?Node\Arg $flagsArg, Scope $scope, array $typeOpt
278
275
/**
279
276
* @return array<string, ?Type>
280
277
*/
281
- private function getOptions (Node \ Arg $ expression , Scope $ scope , string ...$ optionNames ): array
278
+ private function getOptions (Type $ flagsType , string ...$ optionNames ): array
282
279
{
283
280
$ options = [];
284
281
285
- $ exprType = $ scope ->getType ($ expression ->value );
286
- if (!$ exprType instanceof ConstantArrayType) {
282
+ if (!$ flagsType instanceof ConstantArrayType) {
287
283
return $ options ;
288
284
}
289
285
290
- $ optionsType = $ exprType ->getOffsetValueType (new ConstantStringType ('options ' ));
286
+ $ optionsType = $ flagsType ->getOffsetValueType (new ConstantStringType ('options ' ));
291
287
if (!$ optionsType instanceof ConstantArrayType) {
292
288
return $ options ;
293
289
}
@@ -300,13 +296,13 @@ private function getOptions(Node\Arg $expression, Scope $scope, string ...$optio
300
296
return $ options ;
301
297
}
302
298
303
- private function hasFlag (int $ flag , ?Node \ Arg $ expression , Scope $ scope ): bool
299
+ private function hasFlag (int $ flag , ?Type $ flagsType ): bool
304
300
{
305
- if ($ expression === null ) {
301
+ if ($ flagsType === null ) {
306
302
return false ;
307
303
}
308
304
309
- $ type = $ this ->getFlagsValue ($ scope -> getType ( $ expression -> value ) );
305
+ $ type = $ this ->getFlagsValue ($ flagsType );
310
306
311
307
return $ type instanceof ConstantIntegerType && ($ type ->getValue () & $ flag ) === $ flag ;
312
308
}
@@ -320,7 +316,7 @@ private function getFlagsValue(Type $exprType): Type
320
316
return $ exprType ->getOffsetValueType ($ this ->flagsString );
321
317
}
322
318
323
- private function canStringBeSanitized (int $ filterValue , ?Node \ Arg $ flagsArg , Scope $ scope ): bool
319
+ private function canStringBeSanitized (int $ filterValue , ?Type $ flagsType ): bool
324
320
{
325
321
// If it is a validation filter, the string will not be changed
326
322
if (($ filterValue & self ::VALIDATION_FILTER_BITMASK ) !== 0 ) {
@@ -330,9 +326,9 @@ private function canStringBeSanitized(int $filterValue, ?Node\Arg $flagsArg, Sco
330
326
// FILTER_DEFAULT will not sanitize, unless it has FILTER_FLAG_STRIP_LOW,
331
327
// FILTER_FLAG_STRIP_HIGH, or FILTER_FLAG_STRIP_BACKTICK
332
328
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 );
336
332
}
337
333
338
334
return true ;
0 commit comments