,error_levels?:string[]}> */ public function providerValidCodeParse() { return [ 'issetWithSimpleAssignment' => [ ' [], 'error_levels' => ['EmptyArrayAccess'], ], 'issetWithMultipleAssignments' => [ ' 2) { $arr = [5 => [3 => "hello"]]; } if (isset($arr[$a = 5][$b = 3])) { } echo $a; echo $b;', 'assertions' => [], 'error_levels' => ['MixedArrayAccess'], ], 'isset' => [ ' [ '$a' => 'mixed|null', ], 'error_levels' => ['MixedAssignment'], ], 'nullCoalesce' => [ ' [ '$a' => 'mixed|null', ], 'error_levels' => ['MixedAssignment'], ], 'nullCoalesceWithGoodVariable' => [ ' 5 ? "hello" : null; $a = $b ?? null;', 'assertions' => [ '$a' => 'null|string', ], ], 'issetKeyedOffset' => [ ' [ '$foo[\'a\']' => 'mixed|string', ], 'error_levels' => [], ], 'issetKeyedOffsetORFalse' => [ ' "bar"] : false; if (isset($bar["foo"])) { takesString($bar["foo"]); }', 'assertions' => [], 'error_levels' => ['PossiblyInvalidArrayAccess'], ], 'nullCoalesceKeyedOffset' => [ ' [ '$foo[\'a\']' => 'mixed|string', ], 'error_levels' => ['MixedAssignment'], ], 'noRedundantConditionOnMixed' => [ ' [], 'error_levels' => ['MixedAssignment', 'MixedArrayAccess'], ], 'testUnset' => [ ' [ ' [ "foo" => "bar", ], "groups" => [ "foo" => "bar", "hide" => rand() % 2 > 0, ], ]; foreach ($arr as $item) { if (!isset($item["hide"]) || !$item["hide"]) {} }', ], 'issetPropertyAffirmsObject' => [ 'id)) { return $a; } return new A(); }', ], 'issetVariableKeysWithoutChange' => [ ' [ ' $arr */ function foo(array $arr) : int { $b = rand(0, 3); if (!isset($arr[$b])) { throw new \Exception("bad"); } return $arr[$b]; }', ], 'issetArrayOffsetConditionalCreationWithInt' => [ ' $arr */ function foo(array $arr) : string { if (!isset($arr[0])) { $arr[0] = "hello"; } return $arr[0]; }', ], 'issetArrayOffsetConditionalCreationWithVariable' => [ ' $arr */ function foo(array $arr) : string { $b = 5; if (!isset($arr[$b])) { $arr[$b] = "hello"; } return $arr[$b]; }', ], 'noExceptionOnBracketString' => [ ' [ 'b)) { return $arr[1]->b; } throw new \Exception("bad"); }', ], 'allowUnknownAdditionToInt' => [ ' [ ' [ ' [ ' [ ' [ ' [ '> $arr */ function foo(array $arr, string $k) : void { if (!isset($arr[$k])) { return; } if ($arr[$k][0]) {} }', ], 'mixedArrayIsset' => [ ' [], 'error_levels' => ['MixedAssignment', 'MixedArrayAccess'], ], 'mixedArrayIssetGetStringVar' => [ ' [ ' [ ' [ ' [ ' [], 'error_levels' => ['MixedAssignment', 'MixedArgument'], ], 'noParadoxOnMultipleNotIssets' => [ ' [ ' rand(0,1) ? new DateTime : null, "two" => rand(0,1) ? new DateTime : null, "three" => new DateTime ]; if (!(isset($foo["one"]) || isset($foo["two"]))) { exit; } echo $foo["one"]->format("Y");', 'assertions' => [], 'error_levels' => ['PossiblyNullReference'], ], 'notIssetOneOrOtherWithoutAssert' => [ ' rand(0,1) ? new DateTime : null, "two" => rand(0,1) ? new DateTime : null, "three" => new DateTime ]; $a = isset($foo["one"]) || isset($foo["two"]); echo $foo["one"]->format("Y");', 'assertions' => [], 'error_levels' => ['PossiblyNullReference'], ], 'notIssetOneOrOtherWithAssert' => [ ' rand(0,1) ? new DateTime : null, "two" => rand(0,1) ? new DateTime : null, "three" => new DateTime ]; assert(isset($foo["one"]) || isset($foo["two"])); echo $foo["one"]->format("Y");', 'assertions' => [], 'error_levels' => ['PossiblyNullReference'], ], 'assertArrayAfterIssetStringOffset' => [ ' [ ' $val, "text" => $text]; } return $radio; }', 'assertions' => [], 'error_levels' => ['MixedAssignment'], ], 'assertAfterIsset' => [ ' [], 'error_levels' => ['MixedAssignment'], ], 'noCrashAfterIsset' => [ ' [], 'error_levels' => ['MixedAssignment', 'MixedArrayOffset', 'InvalidArrayOffset'], ], 'sessionNullCoalesce' => [ ' [ ' [ ' [ ' [ ' [ ' [ 'c])) { return; } if ($s !== "bar" && isset($a[$b->c])) { // do something } else { // something else } }', ], 'issetOnNestedObjectlikeOneLevel' => [ ' [ ' [ ' [ ' [ ' [ ' [ ' 1, B::class => 2, C::class => 3, ]; public function foo(string $s) : int { $a = static::class; if (!isset(self::MAP[$a])) { throw new \Exception("bad"); } return self::MAP[$a]; } } class A extends P {} class B extends P {} class C extends P {}' ], 'accessAfterArrayExistsStaticClass' => [ ' 1, B::class => 2, C::class => 3, ]; public function foo(string $s) : int { if (!isset(self::MAP[static::class])) { throw new \Exception("bad"); } return self::MAP[static::class]; } } class A extends P {} class B extends P {} class C extends P {}' ], 'issetCreateObjectLikeWithType' => [ ' [ ' [ 's ?? false)) { return "foo"; } return "bar"; }', ], 'issetOnNullableObjectWithIsset' => [ 's) ? $a->s : false)) { return "foo"; } return "bar"; }', ], 'issetOnMethodCallInsideFunctionCall' => [ 'foo() ?? ""); }' ], 'issetOnMethodCallInsideMethodCall' => [ 'foo() ?? ""); }', ], 'methodCallAfterIsset' => [ 'foo)) { return; } if (rand(0, 1)) { $this->foo = new B; } else { $this->foo = new B; } $this->foo->bar(); } }' ], 'SKIPPED-issetOnArrayOfArraysReturningString' => [ ' */ $tokens = []; if (!isset($tokens[$i]["a"])) { /** @psalm-suppress PossiblyUndefinedArrayOffset */ return $tokens[$i]["a"]; } return "hello"; }', ], 'issetOnArrayOfArraysReturningStringInElse' => [ '> */ $tokens = []; if (isset($tokens[$i]["a"])) { return "hello"; } else { return $tokens[$i]["b"]; } }', ], ]; } /** * @return iterable */ public function providerInvalidCodeParse() { return [ 'complainAboutBadCallInIsset' => [ ' 'UndefinedMethod', ], 'issetVariableKeysWithChange' => [ ' 'NullArrayAccess', ], 'issetAdditionalVarWithSealedObjectLike' => [ ' "bat"]; if (isset($params[self::FOO])) { return true; } return false; } }', 'error_message' => 'InvalidArrayOffset', ], 'listDestructuringErrorSuppress' => [ ' 'NullableReturnStatement', ], 'undefinedVarInNullCoalesce' => [ ' 'UndefinedVariable' ], 'issetNullVar' => [ ' 'TypeDoesNotContainType', ], 'stringIsAlwaysSet' => [ ' 'TypeDoesNotContainType' ], 'issetOnArrayOfMixed' => [ ' 'PossiblyUndefinedArrayOffset', ], 'SKIPPED-issetOnArrayOfArrays' => [ ' */ $tokens = []; if (!isset($tokens[$i]["a"])) { echo $tokens[$i]["b"]; } }', 'error_message' => 'PossiblyUndefinedArrayOffset', ], 'SKIPPED-issetOnArrayOfArrayOfStrings' => [ '> */ $tokens = []; if (!isset($tokens[$i]["a"])) { echo $tokens[$i]["b"]; } }', 'error_message' => 'PossiblyUndefinedArrayOffset', ], ]; } }