2017-02-18 02:50:47 +01:00
|
|
|
<?php
|
|
|
|
namespace Psalm\Tests;
|
|
|
|
|
2017-04-25 05:45:02 +02:00
|
|
|
class IssetTest extends TestCase
|
2017-02-18 02:50:47 +01:00
|
|
|
{
|
2017-04-25 05:45:02 +02:00
|
|
|
use Traits\FileCheckerValidCodeParseTestTrait;
|
2018-01-10 01:33:39 +01:00
|
|
|
use Traits\FileCheckerInvalidCodeParseTestTrait;
|
2017-02-18 02:50:47 +01:00
|
|
|
|
|
|
|
/**
|
2017-04-25 05:45:02 +02:00
|
|
|
* @return array
|
2017-02-18 02:50:47 +01:00
|
|
|
*/
|
2017-04-25 05:45:02 +02:00
|
|
|
public function providerFileCheckerValidCodeParse()
|
2017-02-18 02:50:47 +01:00
|
|
|
{
|
2017-04-25 05:45:02 +02:00
|
|
|
return [
|
|
|
|
'isset' => [
|
|
|
|
'<?php
|
|
|
|
$a = isset($b) ? $b : null;',
|
|
|
|
'assertions' => [
|
2017-06-29 16:22:49 +02:00
|
|
|
'$a' => 'mixed',
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
2017-05-27 02:05:57 +02:00
|
|
|
'error_levels' => ['MixedAssignment'],
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'nullCoalesce' => [
|
|
|
|
'<?php
|
|
|
|
$a = $b ?? null;',
|
|
|
|
'assertions' => [
|
2017-06-29 16:22:49 +02:00
|
|
|
'$a' => 'mixed',
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
2017-05-27 02:05:57 +02:00
|
|
|
'error_levels' => ['MixedAssignment'],
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'nullCoalesceWithGoodVariable' => [
|
|
|
|
'<?php
|
2017-11-28 06:46:41 +01:00
|
|
|
$b = rand(0, 10) > 5 ? "hello" : null;
|
2017-04-25 05:45:02 +02:00
|
|
|
$a = $b ?? null;',
|
|
|
|
'assertions' => [
|
2017-11-28 06:46:41 +01:00
|
|
|
'$a' => 'string|null',
|
2017-05-27 02:05:57 +02:00
|
|
|
],
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'issetKeyedOffset' => [
|
|
|
|
'<?php
|
|
|
|
if (!isset($foo["a"])) {
|
|
|
|
$foo["a"] = "hello";
|
|
|
|
}',
|
|
|
|
'assertions' => [
|
2017-06-29 16:22:49 +02:00
|
|
|
'$foo[\'a\']' => 'mixed',
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'error_levels' => [],
|
|
|
|
'scope_vars' => [
|
2017-05-27 02:05:57 +02:00
|
|
|
'$foo' => \Psalm\Type::getArray(),
|
|
|
|
],
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'issetKeyedOffsetORFalse' => [
|
|
|
|
'<?php
|
|
|
|
/** @return void */
|
|
|
|
function takesString(string $str) {}
|
2017-06-29 16:22:49 +02:00
|
|
|
|
2017-04-25 05:45:02 +02:00
|
|
|
$bar = rand(0, 1) ? ["foo" => "bar"] : false;
|
2017-06-29 16:22:49 +02:00
|
|
|
|
2017-04-25 05:45:02 +02:00
|
|
|
if (isset($bar["foo"])) {
|
|
|
|
takesString($bar["foo"]);
|
|
|
|
}',
|
|
|
|
'assertions' => [],
|
2018-01-10 01:33:39 +01:00
|
|
|
'error_levels' => ['PossiblyInvalidArrayAccess'],
|
2017-04-25 05:45:02 +02:00
|
|
|
'scope_vars' => [
|
2017-05-27 02:05:57 +02:00
|
|
|
'$foo' => \Psalm\Type::getArray(),
|
|
|
|
],
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'nullCoalesceKeyedOffset' => [
|
|
|
|
'<?php
|
|
|
|
$foo["a"] = $foo["a"] ?? "hello";',
|
|
|
|
'assertions' => [
|
2017-06-29 16:22:49 +02:00
|
|
|
'$foo[\'a\']' => 'mixed',
|
2017-04-25 05:45:02 +02:00
|
|
|
],
|
|
|
|
'error_levels' => ['MixedAssignment'],
|
|
|
|
'scope_vars' => [
|
2017-05-27 02:05:57 +02:00
|
|
|
'$foo' => \Psalm\Type::getArray(),
|
|
|
|
],
|
|
|
|
],
|
2017-11-28 22:52:52 +01:00
|
|
|
'noRedundantConditionOnMixed' => [
|
|
|
|
'<?php
|
2018-01-11 21:50:45 +01:00
|
|
|
function testarray(array $data): void {
|
2017-11-28 22:52:52 +01:00
|
|
|
foreach ($data as $item) {
|
|
|
|
if (isset($item["a"]) && isset($item["b"]) && isset($item["b"]["c"])) {
|
|
|
|
echo "Found\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}',
|
|
|
|
'assertions' => [],
|
2018-01-10 01:33:39 +01:00
|
|
|
'error_levels' => ['MixedAssignment', 'MixedArrayAccess'],
|
2017-11-28 22:52:52 +01:00
|
|
|
],
|
2017-12-14 01:46:58 +01:00
|
|
|
'testUnset' => [
|
|
|
|
'<?php
|
|
|
|
$foo = ["a", "b", "c"];
|
|
|
|
foreach ($foo as $bar) {}
|
|
|
|
unset($foo, $bar);
|
|
|
|
|
2018-01-11 21:50:45 +01:00
|
|
|
function foo(): void {
|
2017-12-14 01:46:58 +01:00
|
|
|
$foo = ["a", "b", "c"];
|
|
|
|
foreach ($foo as $bar) {}
|
|
|
|
unset($foo, $bar);
|
|
|
|
}',
|
|
|
|
],
|
2017-12-19 00:47:17 +01:00
|
|
|
'issetObjectLike' => [
|
|
|
|
'<?php
|
|
|
|
$arr = [
|
|
|
|
"profile" => [
|
|
|
|
"foo" => "bar",
|
|
|
|
],
|
|
|
|
"groups" => [
|
|
|
|
"foo" => "bar",
|
|
|
|
"hide" => rand() % 2 > 0,
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
foreach ($arr as $item) {
|
|
|
|
if (!isset($item["hide"]) || !$item["hide"]) {}
|
|
|
|
}',
|
|
|
|
],
|
2018-01-29 21:47:25 +01:00
|
|
|
'issetPropertyAffirmsObject' => [
|
|
|
|
'<?php
|
|
|
|
class A {
|
|
|
|
/** @var ?int */
|
|
|
|
public $id;
|
|
|
|
}
|
|
|
|
|
|
|
|
function takesA(?A $a): A {
|
|
|
|
if (isset($a->id)) {
|
|
|
|
return $a;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new A();
|
|
|
|
}',
|
|
|
|
],
|
2018-02-17 17:24:08 +01:00
|
|
|
'issetVariableKeysWithoutChange' => [
|
|
|
|
'<?php
|
|
|
|
$arr = [[1, 2, 3], null, [1, 2, 3], null];
|
|
|
|
$b = 2;
|
|
|
|
$c = 0;
|
|
|
|
if (isset($arr[$b][$c])) {
|
|
|
|
echo $arr[$b][$c];
|
|
|
|
}',
|
|
|
|
],
|
|
|
|
'issetNonNullArrayKey' => [
|
|
|
|
'<?php
|
|
|
|
/**
|
|
|
|
* @param array<int, int> $arr
|
|
|
|
*/
|
|
|
|
function foo(array $arr) : int {
|
|
|
|
$b = rand(0, 3);
|
|
|
|
if (!isset($arr[$b])) {
|
|
|
|
throw new \Exception("bad");
|
|
|
|
}
|
|
|
|
return $arr[$b];
|
|
|
|
}',
|
|
|
|
],
|
|
|
|
'issetArrayOffsetConditionalCreationWithInt' => [
|
|
|
|
'<?php
|
|
|
|
/** @param array<int, string> $arr */
|
|
|
|
function foo(array $arr) : string {
|
|
|
|
if (!isset($arr[0])) {
|
|
|
|
$arr[0] = "hello";
|
|
|
|
}
|
|
|
|
|
|
|
|
return $arr[0];
|
|
|
|
}',
|
|
|
|
],
|
|
|
|
'issetArrayOffsetConditionalCreationWithVariable' => [
|
|
|
|
'<?php
|
|
|
|
/** @param array<int, string> $arr */
|
|
|
|
function foo(array $arr) : string {
|
|
|
|
$b = 5;
|
|
|
|
|
|
|
|
if (!isset($arr[$b])) {
|
|
|
|
$arr[$b] = "hello";
|
|
|
|
}
|
|
|
|
|
|
|
|
return $arr[$b];
|
|
|
|
}',
|
|
|
|
],
|
2018-03-08 21:57:46 +01:00
|
|
|
'noExceptionOnBracketString' => [
|
|
|
|
'<?php
|
|
|
|
if (isset($foo["bar[]"])) {}',
|
|
|
|
],
|
2017-04-25 05:45:02 +02:00
|
|
|
];
|
2017-02-18 02:50:47 +01:00
|
|
|
}
|
2018-01-10 01:33:39 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function providerFileCheckerInvalidCodeParse()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'complainAboutBadCallInIsset' => [
|
|
|
|
'<?php
|
|
|
|
class A {}
|
|
|
|
$a = isset(A::foo()[0]);',
|
|
|
|
'error_message' => 'UndefinedMethod',
|
|
|
|
],
|
2018-02-17 17:24:08 +01:00
|
|
|
'issetVariableKeysWithChange' => [
|
|
|
|
'<?php
|
|
|
|
$arr = [[1, 2, 3], null, [1, 2, 3], null];
|
|
|
|
$b = 2;
|
|
|
|
$c = 0;
|
|
|
|
if (isset($arr[$b][$c])) {
|
|
|
|
$b = 1;
|
|
|
|
echo $arr[$b][$c];
|
|
|
|
}',
|
|
|
|
'error_message' => 'PossiblyNullArrayAccess',
|
|
|
|
],
|
2018-01-10 01:33:39 +01:00
|
|
|
];
|
|
|
|
}
|
2017-02-18 02:50:47 +01:00
|
|
|
}
|