[ 'code' => ' [ '$b===' => '2', '$a===' => '2', ], ], 'updateReferencedTypes' => [ 'code' => ' [ '$a===' => '2', '$b===' => '4', '$c===' => '4', ], ], 'changingReferencedVariableChangesReference' => [ 'code' => ' [ '$a===' => '2', '$b===' => '2', ], ], 'unsetReference' => [ 'code' => ' [ '$a===' => '2', '$b===' => '3', ], ], 'recursiveReference' => [ 'code' => ' [ '$a===' => '2', '$b===' => '2', ], ], 'SKIPPED-referenceToArrayItemChangesArrayType' => [ 'code' => ' */ $arr = []; assert(isset($arr[0])); $int = &$arr[0]; $int = (string) $int; ', 'assertions' => [ '$arr' => 'list', ], ], 'referenceToReference' => [ 'code' => ' [ '$a===' => '2', '$b===' => '3', '$c===' => '2', '$d===' => '3', ], ], 'referenceToSubsequentCatch' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ '$a===' => 'null', '$b===' => 'null', ], ], 'referenceShadowedByGlobal' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => 'bar; $foo->bar = "bar"; ', 'assertions' => [ '$bar===' => "'bar'", ], ], 'referenceReassignedInLoop' => [ 'code' => ' $keys */ function &ensure_array(array &$what, array $keys): array { $arr = & $what; while ($key = array_shift($keys)) { if (!isset($arr[$key]) || !is_array($arr[$key])) { $arr[$key] = array(); } $arr = & $arr[$key]; } return $arr; } ', ], 'dontCrashOnReferenceToMixedVariableArrayOffset' => [ 'code' => ' [], 'ignored_issues' => ['MixedArrayAccess', 'MissingParamType'], ], 'dontCrashOnReferenceToArrayUnknownOffset' => [ 'code' => ' [], ], 'dontCrashOnReferenceToArrayMixedOffset' => [ 'code' => ' [], ], 'allowDocblockTypingOtherVariable' => [ 'code' => ' [ '$b' => 'string', ], ], 'referenceToArrayVariableOffsetDoesntCrashWhenOffsetVariableChangesDueToReconciliation' => [ 'code' => ' ["id" => 1]]; $reference = &$doesNotMatter[$a]; /** @psalm-suppress TypeDoesNotContainType */ $result = ($a === "not-a" && ($b || false)); ', 'assertions' => [ '$reference===' => 'strict-array{id: 1}', ], ], 'multipleReferencesToArrayVariableOffsetThatChangesDueToReconciliation' => [ 'code' => ' ["id" => 1]]; $reference1 = &$doesNotMatter[$a]; $reference2 = &$doesNotMatter[$a]; /** @psalm-suppress TypeDoesNotContainType */ $result = ($a === "not-a" && ($b || false)); $reference1["id"] = 2; ', 'assertions' => [ '$reference1===' => 'strict-array{id: 2}', '$reference2===' => 'strict-array{id: 2}', ], ], ]; } /** * */ public function providerInvalidCodeParse(): iterable { return [ 'referenceReuseForeachValue' => [ 'code' => ' */ $arr = []; foreach ($arr as &$var) { $var += 1; } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referenceReuseDeclaredInForeach' => [ 'code' => ' */ $arr = []; foreach ($arr as $val) { $var = &$val; $var += 1; } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referenceReuseDeclaredInFor' => [ 'code' => ' */ $arr = []; for ($i = 0; $i < count($arr); ++$i) { $var = &$arr[$i]; $var += 1; } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referenceReuseDeclaredInIf' => [ 'code' => ' */ $arr = []; if (isset($arr[0])) { $var = &$arr[0]; $var += 1; } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referenceReuseDeclaredInElseif' => [ 'code' => ' */ $arr = []; if (random_int(0, 1)) { } elseif (isset($arr[0])) { $var = &$arr[0]; $var += 1; } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referenceReuseDeclaredInElse' => [ 'code' => ' */ $arr = []; if (!isset($arr[0])) { } else { $var = &$arr[0]; $var += 1; } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referenceReuseDeeplyNested' => [ 'code' => '>> */ $arr = []; for ($i = 0; $i < count($arr); ++$i) { foreach ($arr[$i] as $inner_arr) { if (isset($inner_arr[0])) { $var = &$inner_arr[0]; $var += 1; } } } $var = "foo"; ', 'error_message' => 'ReferenceReusedFromConfusingScope', ], 'referencesIgnoreVarAnnotation' => [ 'code' => ' 'InvalidDocblock - src' . DIRECTORY_SEPARATOR . 'somefile.php:4:21 - Docblock type cannot be used for reference assignment', ], 'unsetOnlyPreventsReferenceConfusionAfterCall' => [ 'code' => ' 'ReferenceReusedFromConfusingScope', ], 'assignmentAsReferenceOnlyPreventsReferenceConfusionAfterAssignment' => [ 'code' => ' 'ReferenceReusedFromConfusingScope', ], 'unsupportedReferenceUsageWithReferenceToArrayOffsetOfArrayOffset' => [ 'code' => ' */ $arr = []; /** @var non-empty-list */ $foo = ["foo"]; $bar = &$arr[$foo[0]]; ', 'error_message' => 'UnsupportedReferenceUsage', ], 'unsupportedReferenceUsageContinuesAnalysis' => [ 'code' => ' */ $arr = []; /** @var non-empty-list */ $foo = ["foo"]; /** @psalm-suppress UnsupportedReferenceUsage */ $bar = &$arr[$foo[0]]; /** @psalm-trace $bar */; ', 'error_message' => ' - $bar: string', ], ]; } }