,ignored_issues?:list,php_version?:string}> */ public function providerValidCodeParse(): iterable { return [ 'ignoreIssueAndAssign' => [ 'code' => ' [ '$b' => 'null|stdClass', ], 'ignored_issues' => ['RedundantCondition'], ], 'byrefNoRedundantCondition' => [ 'code' => ' [], 'ignored_issues' => [ 'RedundantConditionGivenDocblockType', 'DocblockTypeContradiction', ], ], 'assignmentInIf' => [ 'code' => ' [ 'code' => ' [], ], 'noRedundantConditionAfterDocblockTypeNullCheck' => [ 'code' => 'foo) {} break; default: break; } }', 'assertions' => [], 'ignored_issues' => ['DocblockTypeContradiction'], ], 'noRedundantConditionTypeReplacementWithDocblock' => [ 'code' => ' [], 'ignored_issues' => [ 'DocblockTypeContradiction', ], ], 'noRedundantConditionAfterPossiblyNullCheck' => [ 'code' => ' [], 'ignored_issues' => ['PossiblyUndefinedGlobalVariable'], ], 'noRedundantConditionAfterFromDocblockRemoval' => [ 'code' => 'foo() || $a->bar()) {}', 'assertions' => [], 'ignored_issues' => [ 'DocblockTypeContradiction', ], ], 'noEmptyUndefinedArrayVar' => [ 'code' => ' [], 'ignored_issues' => ['MixedAssignment', 'MixedArrayAccess'], ], 'noComplaintWithIsNumericThenIsEmpty' => [ 'code' => ' [ 'code' => ' 0) { throw new RuntimeException("Failed"); } $value = new stdClass(); if (rand() % 2 > 0) { throw new RuntimeException("Failed"); } } catch (Exception $e) { if ($value) { var_export($value); } } if ($value) {} }', ], 'noRedundantConditionInFalseCheck' => [ 'code' => ' [ 'code' => 'next) {} } }', ], 'noRedundantConditionComparingBool' => [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => [ 'DocblockTypeContradiction', 'RedundantConditionGivenDocblockType', ], ], 'evaluateArrayCheck' => [ 'code' => ' false]; while (rand(0, 1) > 0 && !$data["f"]) { $data = ["f" => true]; } }', ], 'mixedArrayAssignment' => [ 'code' => ' [], 'ignored_issues' => ['MixedAssignment', 'MixedArrayAccess'], ], 'hardPhpTypeAssertionsOnDocblockBoolType' => [ 'code' => ' [], 'ignored_issues' => ['DocblockTypeContradiction'], ], 'hardPhpTypeAssertionsOnDocblockStringType' => [ 'code' => ' [], 'ignored_issues' => ['DocblockTypeContradiction'], ], 'isObjectAssertionOnDocblockType' => [ 'code' => ' [], 'ignored_issues' => ['RedundantConditionGivenDocblockType', 'DocblockTypeContradiction'], ], 'nullToMixedWithNullCheckWithArraykey' => [ 'code' => ' */ function getStrings(): array { return ["hello", "world", 50]; } $a = getStrings(); if (is_string($a[0]) && strlen($a[0]) > 3) {}', 'assignments' => [], 'ignored_issues' => [], ], 'nullToMixedWithNullCheckWithIntKey' => [ 'code' => ' */ function getStrings(): array { return ["hello", "world", 50]; } $a = getStrings(); if (is_string($a[0]) && strlen($a[0]) > 3) {}', 'assignments' => [], 'ignored_issues' => [], ], 'replaceFalseTypeWithTrueConditionalOnMixedEquality' => [ 'code' => ' [], 'ignored_issues' => ['MixedAssignment', 'MissingReturnType', 'MixedArrayAccess'], ], 'nullCoalescePossiblyUndefined' => [ 'code' => ' true]; } /** @psalm-suppress PossiblyUndefinedGlobalVariable */ $option = $options["option"] ?? false; if ($option) {}', 'assignments' => [], 'ignored_issues' => ['MixedAssignment', 'MixedArrayAccess'], ], 'allowIntValueCheckAfterComparisonDueToOverflow' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' "value"]; if (rand(0, 1)) { $x = []; } if ($x) { var_export($x); }', ], 'noRedundantConditionStringNotFalse' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => ['MissingParamType'], ], 'notAlwaysTrueBinaryOp' => [ 'code' => ' [], 'ignored_issues' => ['MissingParamType'], ], 'noRedundantConditionAfterAssertingValue' => [ 'code' => ' [ 'code' => ' [ 'code' => ' $_) { if (rand(0, 1)) { unset($a["foo"][$key]); } } if (empty($a["foo"])) {} } }', 'assertions' => [], 'ignored_issues' => ['MixedAssignment', 'MixedArrayAccess', 'MixedArrayOffset'], ], 'emptyKnowingArrayType' => [ 'code' => '> $a */ function foo(array $a) : void { if (!empty($a["foo"])) { foreach ($a["foo"] as $key => $_) { if (rand(0, 1)) { unset($a["foo"][$key]); } } if (empty($a["foo"])) {} } }', ], 'suppressRedundantConditionAfterAssertNonEmpty' => [ 'code' => ' $a */ function process(array $a): void { assert(!empty($a)); /** @psalm-suppress RedundantConditionGivenDocblockType */ assert(is_int($a[0])); }', ], 'allowChecksOnFalsyIf' => [ 'code' => ' [ 'code' => ' 1]; unset($dict[$s]); if (count($dict)) {} }', ], 'updateArrayAfterUnsetInLoop' => [ 'code' => ' 1, "b" => 2, "c" => 3]; foreach ($arr as $v) { unset($dict[$v]); } if (count($dict)) {} }', ], 'noRedundantConditionWhenAssertingOnIntersection' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' $tokens */ function propertyInUse(array $tokens, int $i): bool { if ($tokens[$i] !== 1) { return false; } $i++; if ($tokens[$i] !== 2) {} return false; }' ], 'invalidateAfterAssignOp' => [ 'code' => ' $tokens */ function propertyInUse(array $tokens, int $i): bool { if ($tokens[$i] !== 1) { return false; } $i += 1; if ($tokens[$i] !== 2) {} return false; }' ], 'invalidateAfterAssign' => [ 'code' => ' $tokens */ function propertyInUse(array $tokens, int $i): bool { if ($tokens[$i] !== 1) { return false; } $i = $i + 1; if ($tokens[$i] !== 2) {} return false; }' ], 'numericNotString' => [ 'code' => ' [ 'code' => ' [ '$fp' => 'closed-resource', ] ], 'allowCheckOnReturnTypeUnion' => [ 'code' => ' [ 'code' => 'closed) { return function() : void { if ($this->closed) {} }; } return function() : void {}; } }' ], 'noRedundantCastAfterCalculation' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'NumericCanBeFalsy' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'NumericCanBeNotIntOrNotFloat' => [ 'code' => ' [ 'code' => 'get()) && rand(0,1)){ } ' ], 'alwaysTrueAssignAllowedInsideOr' => [ 'code' => 'get() || ($c = rand(0,1))){ } ' ], 'countWithNeverValuesInKeyedArray' => [ 'code' => ' [ 'code' => ',php_version?:string}> */ public function providerInvalidCodeParse(): iterable { return [ 'ifFalse' => [ 'code' => ' 'TypeDoesNotContainType', ], 'ifNotTrue' => [ 'code' => ' 'TypeDoesNotContainType', ], 'ifTrue' => [ 'code' => ' 'RedundantCondition', ], 'unnecessaryInstanceof' => [ 'code' => 'fooFoo(); }', 'error_message' => 'RedundantCondition', ], 'failedTypeResolution' => [ 'code' => ' 'RedundantCondition', ], 'failedTypeResolutionWithDocblock' => [ 'code' => ' 'RedundantCondition', ], 'typeResolutionFromDocblockAndInstanceof' => [ 'code' => ' 'RedundantCondition', ], 'typeResolutionRepeatingConditionWithSingleVar' => [ 'code' => ' 5; if ($a && $a) {}', 'error_message' => 'RedundantCondition', ], 'typeResolutionRepeatingConditionWithVarInMiddle' => [ 'code' => ' 5; $b = rand(0, 10) > 5; if ($a && $b && $a) {}', 'error_message' => 'RedundantCondition', ], 'typeResolutionRepeatingOredConditionWithSingleVar' => [ 'code' => ' 5; if ($a || $a) {}', 'error_message' => 'TypeDoesNotContainType', ], 'typeResolutionRepeatingOredConditionWithVarInMiddle' => [ 'code' => ' 5; $b = rand(0, 10) > 5; if ($a || $b || $a) {}', 'error_message' => 'TypeDoesNotContainType', ], 'typeResolutionIsIntAndIsNumeric' => [ 'code' => ' 5 ? "hello" : 3; if (is_int($c) && is_numeric($c)) {}', 'error_message' => 'RedundantCondition', ], 'typeResolutionWithInstanceOfAndNotEmpty' => [ 'code' => ' 5 ? new stdClass : null; if ($x instanceof stdClass && $x) {}', 'error_message' => 'RedundantCondition', ], 'methodWithMeaninglessCheck' => [ 'code' => 'fooFoo(); } }', 'error_message' => 'TypeDoesNotContainType', ], 'twoVarLogicNotNestedWithElseifNegatedInIf' => [ 'code' => ' 'RedundantCondition', ], 'refineTypeInMethodCall' => [ 'code' => ' 'RedundantCondition - src' . DIRECTORY_SEPARATOR . 'somefile.php:15', ], 'replaceFalseType' => [ 'code' => ' 'RedundantCondition', ], 'replaceTrueType' => [ 'code' => ' 'TypeDoesNotContainType - src' . DIRECTORY_SEPARATOR . 'somefile.php:7', ], 'disallowFloatCheckAfterSettingToVar' => [ 'code' => ' 'TypeDoesNotContainType - src' . DIRECTORY_SEPARATOR . 'somefile.php:7', ], 'disallowTwoIntValueChecksDueToConditionalOverflow' => [ 'code' => ' 'TypeDoesNotContainType - src' . DIRECTORY_SEPARATOR . 'somefile.php:6', ], 'redundantEmptyArray' => [ 'code' => ' "value"]; if ($x) { var_export($x); }', 'error_message' => 'RedundantCondition', ], 'redundantConditionStringNotFalse' => [ 'code' => ' 'RedundantCondition', ], 'redundantConditionStringNotTrue' => [ 'code' => ' 'RedundantCondition', ], 'redundantConditionAfterRemovingFalse' => [ 'code' => ' 'RedundantCondition', ], 'redundantConditionAfterRemovingTrue' => [ 'code' => ' 'RedundantCondition', ], 'impossibleNullEquality' => [ 'code' => ' 'RedundantCondition', ], 'impossibleTrueEquality' => [ 'code' => ' 'RedundantCondition', ], 'impossibleFalseEquality' => [ 'code' => ' 'RedundantCondition', ], 'impossibleNumberEquality' => [ 'code' => ' 'RedundantCondition', ], 'alwaysTrueBinaryOp' => [ 'code' => ' 'RedundantCondition', 'ignored_issues' => ['MissingParamType'], ], 'negatedInstanceof' => [ 'code' => ' 'RedundantCondition', ], 'redundantInstanceof' => [ 'code' => ' 'RedundantConditionGivenDocblockType', ], 'preventDocblockTypesBeingIdenticalToTrue' => [ 'code' => ' 'DocblockTypeContradiction', ], 'preventDocblockTypesBeingIdenticalToTrueReversed' => [ 'code' => ' 'DocblockTypeContradiction', ], 'preventDocblockTypesBeingIdenticalToFalse' => [ 'code' => ' 'DocblockTypeContradiction', ], 'preventDocblockTypesBeingIdenticalToFalseReversed' => [ 'code' => ' 'DocblockTypeContradiction', ], 'preventDocblockTypesBeingSameAsEmptyArrayReversed' => [ 'code' => ' 'DocblockTypeContradiction', ], 'preventDocblockTypesBeingIdenticalToEmptyArrayReversed' => [ 'code' => ' 'DocblockTypeContradiction', ], 'preventTypesBeingIdenticalToEmptyArrayReversed' => [ 'code' => ' 'TypeDoesNotContainType', ], 'SKIPPED-secondInterfaceAssertionIsRedundant' => [ 'code' => ' 'RedundantConditionGivenDocblockType', ], 'errorAfterStatementThatCannotBeConvertedToAssertion' => [ 'code' => ' 'RedundantCondition', ], 'noLongerWarnsAboutRedundancyHere' => [ 'code' => ' 'RedundantCondition', ], 'prohibitFalsyChecksOnPropertiesWithMethodCall' => [ 'code' => 'headers = $headers; } } function lag(Request $req) : void { if ($req->headers && $req->headers->has("foo")) {} }', 'error_message' => 'RedundantCondition', ], 'prohibitFalsyChecksOnPropertiesWithoutMethodCall' => [ 'code' => 'headers = $headers; } } function lag(Request $req) : void { if ($req->headers) {} }', 'error_message' => 'RedundantCondition', ], 'checkResourceTwice' => [ 'code' => ' 'RedundantCondition', ], 'preventAlwaysReturningInt' => [ 'code' => ' 'RedundantCondition', ], 'preventAlwaysReturningSpecificInt' => [ 'code' => ' 'RedundantConditionGivenDocblockType', ], 'preventNotAlwaysReturningInt' => [ 'code' => ' 'TypeDoesNotContainType', ], 'classAlwaysParent' => [ 'code' => ' 'RedundantCondition', ], 'staticClassIsAlwaysNull' => [ 'code' => ' 'RedundantConditionGivenDocblockType', ], 'classStringNotEmpty' => [ 'code' => ' 'RedundantCondition', ], 'leftCannotBeTrue' => [ 'code' => ' 'DocblockTypeContradiction', ], 'rightCannotBeTrue' => [ 'code' => ' 'DocblockTypeContradiction', ], 'OrTrue' => [ 'code' => ' 'RedundantCondition', ], 'AndTrue' => [ 'code' => ' 'RedundantCondition', ], 'OrFalse' => [ 'code' => ' 'TypeDoesNotContainType', ], 'AndFalse' => [ 'code' => ' 'TypeDoesNotContainType', ], 'alwaysTrueAssign' => [ 'code' => 'get()){ } ', 'error_message' => 'RedundantCondition', ], 'secondFalsyTwiceWithoutChange' => [ 'code' => ' 'RedundantCondition' ], 'secondFalsyTwiceWithoutChangeWithElse' => [ 'code' => ' 'RedundantCondition' ], ]; } }