addFile( 'somefile.php', ' 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); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->project_checker->checkClassReferences(); $this->assertSame('array', (string) $context->vars_in_scope['$d']); $this->assertSame('array', (string) $context->vars_in_scope['$e']); } /** * @return void */ public function testArrayFilterAdvanced() { if (version_compare((string)PHP_VERSION, '5.6.0', '>=')) { $this->addFile( 'somefile.php', ' 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); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->project_checker->checkClassReferences(); $this->assertSame('array', (string) $context->vars_in_scope['$f']); $this->assertSame('array', (string) $context->vars_in_scope['$g']); } } /** * @return void */ public function testArrayFilterUseKey() { if (version_compare((string)PHP_VERSION, '5.6.0', '>=')) { $this->addFile( getcwd() . '/src/somefile.php', ' function () : string { return "baz"; }, ]; $foo = array_filter( $foo, function (string $key) : bool { return $key === "bar"; }, ARRAY_FILTER_USE_KEY );' ); $file_checker = new FileChecker(getcwd() . '/src/somefile.php', $this->project_checker); $context = new Context(); $file_checker->visitAndAnalyzeMethods($context); $this->project_checker->checkClassReferences(); } } /** * @return array */ public function providerFileCheckerValidCodeParse() { return [ 'typedArrayWithDefault' => [ ' $a */ function fooFoo(array $a = []) : void { }', ], 'typedArrayWithDefault' => [ ' [ '$a' => 'int', '$b' => 'int', ], ], 'validDocblockParamDefault' => [ ' [ ' [ ' [ ' [ ' [ ' 1, "b" => 2]);', 'assertions' => [ '$a' => 'array', ], ], 'arrayKeysMixed' => [ ' 5]; $a = array_keys($b);', 'assertions' => [ '$a' => 'array', ], 'error_levels' => ['MixedArgument'], ], 'arrayValues' => [ ' 1, "b" => 2]);', 'assertions' => [ '$b' => 'array', ], ], 'arrayCombine' => [ ' [ '$c' => 'array', ], ], 'arrayMerge' => [ ' [ '$d' => 'array{0:string, 1:string, 2:string, 3:int, 4:int, 5:int}', ], ], 'arrayDiff' => [ ' 5, "b" => 12], [5]);', 'assertions' => [ '$d' => 'array', ], ], 'arrayPopMixed' => [ ' 5, "c" => 6]; $a = array_pop($b);', 'assertions' => [ '$a' => 'mixed', '$b' => 'mixed', ], 'error_levels' => ['MixedAssignment', 'MixedArgument'], ], 'uasort' => [ ' [], 'error_levels' => ['MixedArrayAccess', 'MixedArgument', 'UntypedParam', 'MissingClosureReturnType'], ], 'byRefAfterCallable' => [ ' [], 'error_levels' => [ 'MixedAssignment', 'MixedArrayAccess', ], ], 'extractVarCheck' => [ ' "bar"]; extract($a); takesString($foo);', 'assertions' => [], 'error_levels' => [ 'MixedAssignment', 'MixedArrayAccess', ], ], 'arrayMergeObjectLike' => [ ' $a * @return array */ function foo($a) { return $a; } $a1 = ["hi" => 3]; $a2 = ["bye" => 5]; $a3 = array_merge($a1, $a2); foo($a3);', 'assertions' => [ '$a3' => 'array{hi:int, bye:int}', ], ], 'goodByRef' => [ 'foo); fooFoo($b);', ], 'arrayRand' => [ ' "a", "y" => "b"]; $c = array_rand($vars); $d = $vars[$c]; $more_vars = ["a", "b"]; $e = array_rand($more_vars);', 'assertions' => [ '$vars' => 'array{x:string, y:string}', '$c' => 'string', '$d' => 'string', '$more_vars' => 'array{0:string, 1:string}', '$e' => 'int', ], ], 'arrayRandMultiple' => [ ' "a", "y" => "b"]; $b = 3; $c = array_rand($vars, 1); $d = array_rand($vars, 2); $e = array_rand($vars, 3); $f = array_rand($vars, $b);', 'assertions' => [ '$vars' => 'array{x:string, y:string}', '$c' => 'string', '$e' => 'array', '$f' => 'array|string', ], ], 'arrayKeysNoEmpty' => [ ' [], 'error_levels' => ['MixedAssignment', 'MixedArgument'], ], 'compact' => [ ' [ ' $b */ function a($b) : string { return $b["a"]; } a(["a" => "hello"]);', ], 'objectLikeKeyChecksAgainstObjectLike' => [ ' "hello"]);', ], ]; } /** * @return array */ public function providerFileCheckerInvalidCodeParse() { return [ 'invalidScalarArgument' => [ ' 'InvalidScalarArgument', ], 'mixedArgument' => [ ' 'MixedArgument', 'error_levels' => ['MixedAssignment'], ], 'nullArgument' => [ ' 'NullArgument', ], 'tooFewArguments' => [ ' 'TooFewArguments', ], 'tooManyArguments' => [ ' 'TooManyArguments', ], 'tooManyArgumentsForConstructor' => [ ' 'TooManyArguments', ], 'typeCoercion' => [ ' 'TypeCoercion', ], 'arrayTypeCoercion' => [ ' 'TypeCoercion', ], 'duplicateParam' => [ ' 'DuplicateParam', 'error_levels' => ['UntypedParam'], ], 'invalidParamDefault' => [ ' 'InvalidParamDefault', ], 'invalidDocblockParamDefault' => [ ' 'InvalidParamDefault', ], 'badByRef' => [ ' 'InvalidPassByReference', ], 'badArrayByRef' => [ ' 'InvalidPassByReference', ], 'invalidArgAfterCallable' => [ ' 'InvalidScalarArgument', 'error_levels' => [ 'MixedAssignment', 'MixedArrayAccess', ], ], 'undefinedFunctionInArrayMap' => [ ' 'UndefinedFunction', ], 'objectLikeKeyChecksAgainstDifferentGeneric' => [ ' $b */ function a($b) : int { return $b["a"]; } a(["a" => "hello"]);', 'error_message' => 'InvalidScalarArgument', ], 'objectLikeKeyChecksAgainstDifferentObjectLike' => [ ' "hello"]);', 'error_message' => 'InvalidScalarArgument', ], ]; } }