parse(' 5, "b" => 12, "c" => null]); $e = array_filter(["a" => 5, "b" => 12, "c" => null], function(?int $i) : bool { return true; }); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$d']); $this->assertEquals('array', (string) $context->vars_in_scope['$e']); if (version_compare((string)phpversion(), '5.6.0', '>=')) { $stmts = self::$parser->parse(' 5, "b" => 12, "c" => null], function(?int $val, string $key) : bool { return true; }, ARRAY_FILTER_USE_BOTH); $g = array_filter(["a" => 5, "b" => 12, "c" => null], function(string $val) : bool { return true; }, ARRAY_FILTER_USE_KEY); $bar = "bar"; $foo = [ $bar => function () : string { return "baz"; }, ]; $foo = array_filter( $foo, function (string $key) : bool { return $key === "bar"; }, ARRAY_FILTER_USE_KEY ); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->assertEquals('array', (string) $context->vars_in_scope['$f']); $this->assertEquals('array', (string) $context->vars_in_scope['$g']); } } /** * @return void */ public function testArrayFilterUseKey() { if (version_compare((string)phpversion(), '5.6.0', '>=')) { $stmts = self::$parser->parse(' function () : string { return "baz"; }, ]; $foo = array_filter( $foo, function (string $key) : bool { return $key === "bar"; }, ARRAY_FILTER_USE_KEY ); '); $file_checker = new FileChecker('somefile.php', $this->project_checker, $stmts); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); } } /** * @return array */ public function providerFileCheckerValidCodeParse() { return [ 'typedArrayWithDefault' => [ ' $a */ function fooFoo(array $a = []) : void { }' ], 'validDocblockParamDefault' => [ ' [ ' [ ' [ ' [ ' [ ' 1, "b" => 2]);', 'assertions' => [ ['array' => '$a'] ] ], 'arrayKeysMixed' => [ ' 5]; $a = array_keys($b);', 'assertions' => [ ['array' => '$a'] ], 'error_levels' => ['MixedArgument'] ], 'arrayValues' => [ ' 1, "b" => 2]);', 'assertions' => [ ['array' => '$b'] ] ], 'arrayCombine' => [ ' [ ['array' => '$c'] ] ], 'arrayMerge' => [ ' [ ['array' => '$d'] ] ], 'arrayDiff' => [ ' 5, "b" => 12], [5]);', 'assertions' => [ ['array' => '$d'] ] ], 'byRefAfterCallable' => [ ' [], 'error_levels' => [ 'MixedAssignment', 'MixedArrayAccess' ] ], 'extractVarCheck' => [ ' "bar"]; extract($a); takesString($foo);', 'assertions' => [], 'error_levels' => [ 'MixedAssignment', 'MixedArrayAccess' ] ] ]; } /** * @return array */ public function providerFileCheckerInvalidCodeParse() { return [ 'invalidScalarArgument' => [ ' 'InvalidScalarArgument' ], 'mixedArgument' => [ ' 'MixedArgument', 'error_levels' => ['MixedAssignment'] ], 'nullArgument' => [ ' 'NullArgument' ], 'tooFewArguments' => [ ' 'TooFewArguments' ], 'tooManyArguments' => [ ' 'TooManyArguments' ], 'typeCoercion' => [ ' 'TypeCoercion' ], 'arrayTypeCoercion' => [ ' 'TypeCoercion' ], 'duplicateParam' => [ ' 'DuplicateParam' ], 'invalidParamDefault' => [ ' 'InvalidParamDefault' ], 'invalidDocblockParamDefault' => [ ' 'InvalidParamDefault' ], // Skipped. Does not throw an error. 'SKIPPED-badByRef' => [ ' 'InvalidPassByReference' ], 'invalidArgAfterCallable' => [ ' 'InvalidScalarArgument', 'error_levels' => [ 'MixedAssignment', 'MixedArrayAccess' ] ] ]; } }