[ 'code' => ' */ final class FirstMessage implements Message {} /** @implements Message */ final class SecondMessage implements Message {} /** * @template T * @param Message $msg */ function test(Message $msg): void {} /** @var FirstMessage|SecondMessage $message */; test($message);', 'assertions' => [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'callFunctionWithTemplateClassStringWillNotFail' => [ 'code' => '> $classString */ function acceptTemplatedClassString(string $classString): void { } /** @param class-string> $classString */ function app(string $classString): void { acceptTemplatedClassString($classString); }', ], 'inferGenericListFromTuple' => [ 'code' => ' $list * @return list */ function testList(array $list): array { return $list; } /** * @template A * @param non-empty-list $list * @return non-empty-list */ function testNonEmptyList(array $list): array { return $list; } /** * @template A of list * @param A $list * @return A */ function testGenericList(array $list): array { return $list; } $list = testList([1, 2, 3]); $nonEmptyList = testNonEmptyList([1, 2, 3]); $genericList = testGenericList([1, 2, 3]);', 'assertions' => [ '$list===' => 'list<1|2|3>', '$nonEmptyList===' => 'non-empty-list<1|2|3>', '$genericList===' => 'list{1, 2, 3}', ], ], 'inferIterableFromTraversable' => [ 'code' => ' */ function getStrings(): SplFixedArray { return SplFixedArray::fromArray(["fst", "snd", "thr"]); } /** * @return SplFixedArray */ function getIntegers(): SplFixedArray { return SplFixedArray::fromArray([1, 2, 3]); } /** * @template K * @template A * @template B * @param iterable $lhs * @param iterable $rhs * @return iterable */ function mergeIterable(iterable $lhs, iterable $rhs): iterable { foreach ($lhs as $k => $v) { yield $k => $v; } foreach ($rhs as $k => $v) { yield $k => $v; } } $iterable = mergeIterable(getStrings(), getIntegers());', 'assertions' => [ '$iterable===' => 'iterable', ], ], 'inferTypeFromAnonymousObjectWithTemplatedProperty' => [ 'code' => 'value; } /** * @template T * @param object{value: object{value: T}} $object * @return T */ function getNestedValue(object $object): mixed { return $object->value->value; } $object = new Value(new Value(42)); $value = getValue($object); $nestedValue = getNestedValue($object);', 'assertions' => [ '$value===' => 'Value<42>', '$nestedValue===' => '42', ], 'ignored_issues' => [], 'php_version' => '8.1', ], 'inferTypeFromAnonymousObjectWithTemplatedPropertyFromTemplatedAncestor' => [ 'code' => ' */ final class ConcreteValue extends AbstractValue { /** * @param TValue $value */ public function __construct(mixed $value) { parent::__construct($value); } } /** * @template T * @param object{value: T} $object * @return T */ function getValue(object $object): mixed { return $object->value; } /** * @template T * @param object{value: object{value: T}} $object * @return T */ function getNestedValue(object $object): mixed { return $object->value->value; } $object = new ConcreteValue(new ConcreteValue(42)); $value = getValue($object); $nestedValue = getNestedValue($object);', 'assertions' => [ '$value===' => 'ConcreteValue<42>', '$nestedValue===' => '42', ], 'ignored_issues' => [], 'php_version' => '8.1', ], 'inferTypeFromAnonymousObjectWithTemplatedPropertyFromConcreteAncestor' => [ 'code' => ' */ final class IntValue extends AbstractValue {} final class Nested { public function __construct(public readonly IntValue $value) {} } /** * @template T * @param object{value: T} $object * @return T */ function getValue(object $object): mixed { return $object->value; } /** * @template T * @param object{value: object{value: T}} $object * @return T */ function getNestedValue(object $object): mixed { return $object->value->value; } $object = new Nested(new IntValue(42)); $value = getValue($object); $nestedValue = getNestedValue($object);', 'assertions' => [ '$value===' => 'IntValue', '$nestedValue===' => 'int', ], 'ignored_issues' => [], 'php_version' => '8.1', ], 'countShapedArrays' => [ 'code' => ' [ '$aCount===' => 'int<0, 1>', '$bCount===' => '1', '$cCount===' => 'int<1, 2>', '$dCount===' => 'int<1, max>', '$eCount===' => 'int<0, 1>', '$fCount===' => '1', '$gCount===' => 'int<1, 2>', '$hCount===' => 'int<1, max>', ], ], 'preg_grep' => [ 'code' => ' $strings * @return array */ function filter(array $strings): array { return preg_grep("/search/", $strings, PREG_GREP_INVERT); } ', ], 'typedArrayWithDefault' => [ 'code' => ' $a */ function fooFoo(array $a = []): void { }', ], 'abs' => [ 'code' => ' [ '$a' => 'int<0, max>', '$b' => 'float', '$c' => 'float|int<0, max>|null', ], 'ignored_issues' => ['MixedAssignment', 'MixedArgument'], ], 'validDocblockParamDefault' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => 'foo);', ], 'namespaced' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' */ $a = []; $b = 5; if (count($a)) {}', ], 'noRedundantConditionAfterMixedOrEmptyArrayCountCheck' => [ 'code' => ' [], 'ignored_issues' => ['MixedAssignment', 'MixedArgument'], ], 'objectLikeArrayAssignmentInConditional' => [ 'code' => ' [ 'code' => ' [ 'code' => ' */ public $arr = []; } /** @var array */ $replacement_stmts = []; if (!$replacement_stmts || !$replacement_stmts[0] instanceof B || count($replacement_stmts[0]->arr) > 1 ) { return null; } $b = $replacement_stmts[0]->arr;', 'assertions' => [ '$b' => 'array', ], ], 'countMoreThan0CanBeInverted' => [ 'code' => ' 0) { exit; }', 'assertions' => [ '$a' => 'array', ], ], 'countCheckOnNonEmptyArray' => [ 'code' => ' $arr */ function foo(array $arr): void { if (count($arr) > 5) {} }', ], 'byRefAfterCallable' => [ 'code' => ' [], 'ignored_issues' => [ 'MixedAssignment', 'MixedArrayAccess', 'RedundantConditionGivenDocblockType', ], ], 'ignoreNullablePregReplace' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => [ 'MixedArgument', ], ], 'extractVarCheckValid' => [ 'code' => ' 15]; extract($a); takesInt($foo);', ], 'extractSkipExtr' => [ 'code' => ' "x", "b" => "y"], EXTR_SKIP);', 'assertions' => [ '$a===' => '1', '$b===' => '\'y\'', ], ], 'compact' => [ 'code' => ' */ function test(): array { return compact(["val"]); }', ], 'objectLikeKeyChecksAgainstGeneric' => [ 'code' => ' $b */ function a($b): string { return $b["a"]; } a(["a" => "hello"]);', ], 'objectLikeKeyChecksAgainstTKeyedArray' => [ 'code' => ' "hello"]);', ], 'getenv' => [ 'code' => ' [ '$a' => 'array', '$b' => 'false|string', ], ], 'ignoreFalsableFileGetContents' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ '$a' => 'string', ], ], 'varExportConstFetch' => [ 'code' => ' [ 'code' => ' [ '$elements' => 'non-empty-list', ], ], 'explodeWithPositiveLimit' => [ 'code' => ' [ '$elements' => 'non-empty-list', ], ], 'explodeWithNegativeLimit' => [ 'code' => ' [ '$elements' => 'list', ], ], 'explodeWithDynamicLimit' => [ 'code' => ' [ '$elements' => 'list{0?: string, 1?: string, 2?: string, ...}', ], ], 'explodeWithDynamicDelimiter' => [ 'code' => ' [ '$elements' => 'non-empty-list', ], ], 'explodeWithDynamicDelimiterAndSmallPositiveLimit' => [ 'code' => ' [ '$elements' => 'list{0: string, 1?: string}', ], ], 'explodeWithDynamicDelimiterAndPositiveLimit' => [ 'code' => ' [ '$elements' => 'non-empty-list', ], ], 'explodeWithDynamicDelimiterAndNegativeLimit' => [ 'code' => ' [ '$elements' => 'list', ], ], 'explodeWithDynamicDelimiterAndLimit' => [ 'code' => ' [ '$elements' => 'list{0?: string, 1?: string, 2?: string, ...}', ], ], 'explodeWithDynamicNonEmptyDelimiter' => [ 'code' => ' [ '$elements' => 'non-empty-list', ], ], 'explodeWithLiteralNonEmptyDelimiter' => [ 'code' => ' [ '$elements' => 'non-empty-list', ], ], 'explodeWithPossiblyFalse' => [ 'code' => ' */ function exploder(string $d, string $s) : array { return explode($d, $s); }', ], 'allowPossiblyUndefinedClassInClassExists' => [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => ['MixedMethodCall'], ], 'next' => [ 'code' => ' [ '$n' => 'false|string', ], ], 'iteratorToArray' => [ 'code' => ' */ function generator(): Generator { yield new stdClass; } $a = iterator_to_array(generator());', 'assertions' => [ '$a' => 'array', ], ], 'iteratorToArrayWithGetIterator' => [ 'code' => ' */ class C implements IteratorAggregate { /** * @return Traversable */ public function getIterator() { yield 1 => "1"; } } $a = iterator_to_array(new C);', 'assertions' => [ '$a' => 'array', ], ], 'iteratorToArrayWithGetIteratorReturningList' => [ 'code' => ' */ class C implements IteratorAggregate { /** * @return Traversable */ public function getIterator() { yield 1 => "1"; } } $a = iterator_to_array(new C, false);', 'assertions' => [ '$a' => 'list', ], ], 'strtrWithPossiblyFalseFirstArg' => [ 'code' => ' $replace_pairs * @return string */ function strtr_wrapper($str, array $replace_pairs) { /** @psalm-suppress PossiblyFalseArgument */ return strtr($str, $replace_pairs); }', ], 'versionCompare' => [ 'code' => ' [ '$a' => 'int', '$b' => 'bool', '$c' => 'bool', ], ], 'getTimeOfDay' => [ 'code' => ' [ '$a' => 'float', '$b' => 'array', '$c' => 'array', ], ], 'parseUrlArray' => [ 'code' => ' [ '$porta' => 'false|int|null', '$porte' => 'false|int|null', ], 'ignored_issues' => ['MixedReturnStatement', 'MixedInferredReturnType'], ], 'parseUrlComponent' => [ 'code' => ' [ 'code' => ' [ '$components' => 'array{fragment?: string, host?: string, pass?: string, path?: string, port?: int, query?: string, scheme?: string, user?: string}|false', '$scheme' => 'false|null|string', '$host' => 'false|null|string', '$port' => 'false|int|null', '$user' => 'false|null|string', '$pass' => 'false|null|string', '$path' => 'false|null|string', '$query' => 'false|null|string', '$fragment' => 'false|null|string', ], ], 'parseUrlDefaultComponent' => [ 'code' => ' [ '$a' => 'array{fragment?: string, host?: string, pass?: string, path?: string, port?: int, query?: string, scheme?: string, user?: string}|false', '$b' => 'array{fragment?: string, host?: string, pass?: string, path?: string, port?: int, query?: string, scheme?: string, user?: string}|false', '$c' => 'array{fragment?: string, host?: string, pass?: string, path?: string, port?: int, query?: string, scheme?: string, user?: string}|false', ], ], 'triggerUserError' => [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => ['MixedMethodCall'], ], 'suppressError' => [ 'code' => ' [ '$a' => 'false|string', ], ], 'echo' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ '$a' => 'float', '$b' => 'string', '$c' => 'float|string', '$d' => 'string', ], ], 'filterInput' => [ 'code' => ' ["default" => null]]); } function filterIntWithDefault(string $s) : int { return filter_var($s, FILTER_VALIDATE_INT, ["options" => ["default" => 5]]); } function filterBool(string $s) : bool { return filter_var($s, FILTER_VALIDATE_BOOLEAN); } function filterNullableBool(string $s) : ?bool { return filter_var($s, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); } function filterNullableBoolWithFlagsArray(string $s) : ?bool { return filter_var($s, FILTER_VALIDATE_BOOLEAN, ["flags" => FILTER_NULL_ON_FAILURE]); } function filterFloat(string $s) : float { $filtered = filter_var($s, FILTER_VALIDATE_FLOAT); if ($filtered === false) { return 0.0; } return $filtered; } function filterFloatWithDefault(string $s) : float { return filter_var($s, FILTER_VALIDATE_FLOAT, ["options" => ["default" => 5.0]]); }', ], 'filterVar' => [ 'code' => ' ["default" => null]]); } function filterIntWithDefault(string $s) : int { return filter_var($s, FILTER_VALIDATE_INT, ["options" => ["default" => 5]]); } function filterBool(string $s) : bool { return filter_var($s, FILTER_VALIDATE_BOOLEAN); } function filterNullableBool(string $s) : ?bool { return filter_var($s, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); } function filterNullableBoolWithFlagsArray(string $s) : ?bool { return filter_var($s, FILTER_VALIDATE_BOOLEAN, ["flags" => FILTER_NULL_ON_FAILURE]); } function filterFloat(string $s) : float { $filtered = filter_var($s, FILTER_VALIDATE_FLOAT); if ($filtered === false) { return 0.0; } return $filtered; } function filterFloatWithDefault(string $s) : float { return filter_var($s, FILTER_VALIDATE_FLOAT, ["options" => ["default" => 5.0]]); }', ], 'callVariableVar' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ '$a' => 'non-empty-list', '$b' => 'non-empty-list', '$c' => 'non-empty-list', ], ], 'duplicateNamespacedFunction' => [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => ['UndefinedConstant', 'UnresolvableInclude'], ], 'noNamespaceClash' => [ 'code' => ' [ 'code' => ' [ '$h' => 'resource', ], 'ignored_issues' => [], 'php_version' => '7.1', ], 'hashInit71' => [ 'code' => ' [ '$h' => 'resource', ], 'ignored_issues' => [], 'php_version' => '7.1', ], 'hashInit72' => [ 'code' => ' [ '$h' => 'HashContext|false', ], 'ignored_issues' => [], 'php_version' => '7.2', ], 'hashInit73' => [ 'code' => ' [ '$h' => 'HashContext|false', ], 'ignored_issues' => [], 'php_version' => '7.3', ], 'hashInit80' => [ 'code' => ' [ '$h' => 'HashContext', ], 'ignored_issues' => [], 'php_version' => '8.0', ], 'nullableByRef' => [ 'code' => ' [ 'code' => '[] */ public $arr = []; } (new Props)->arr[] = get_class(new C);', ], 'getClassVariable' => [ 'code' => '[] */ public $arr = []; } (new Props)->arr[] = get_class($c_instance);', ], 'getClassAnonymousNewInstance' => [ 'code' => '[] */ public $arr = []; } (new Props)->arr[] = get_class(new class implements I{});', ], 'getClassAnonymousVariable' => [ 'code' => '[] */ public $arr = []; } (new Props)->arr[] = get_class($anon_instance);', ], 'mktime' => [ 'code' => ' [ '$a' => 'false|int', '$b' => 'false|int', '$c' => 'int', ], ], 'hrtime' => [ 'code' => ' [ '$a' => 'int', '$b' => 'list{int, int}', '$c' => 'int|list{int, int}', '$d' => 'list{int, int}', ], ], 'hrtimeCanBeFloat' => [ 'code' => ' [ 'code' => ' [ '$a' => 'int', '$b' => 'int', '$c' => 'string', '$d' => 'int', '$e' => 'int', '$f' => 'int', ], ], 'minUnpackedArg' => [ 'code' => ' [ '$f' => 'int', ], ], 'sscanf' => [ 'code' => ' [ '$hours' => 'float|int|null|string', '$minutes' => 'float|int|null|string', '$seconds' => 'float|int|null|string', ], ], 'noImplicitAssignmentToStringFromMixedWithDocblockTypes' => [ 'code' => ' [ 'code' => ' [ 'code' => '"); echo count($xml);', ], 'countableCallableArray' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' $x * @return 0 */ function example($x) : int { return count($x); }', ], 'countConstantSizeArrayShouldBeConstantInteger' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => 'bar(); }', ], 'functionExists' => [ 'code' => ' [ 'code' => <<<'PHP' [ 'code' => ' [ 'code' => ' [ '$r===' => '0|1|false', ], ], 'pregMatchWithMatches' => [ 'code' => ' [ 'code' => ' [ '$r===' => '0|1|false', '$matches===' => 'array', ], ], 'pregMatchWithOffset' => [ 'code' => ' [ 'code' => ' [ '$r===' => '0|1|false', '$matches===' => 'array', ], ], 'pregMatchWithFlags' => [ 'code' => ' [ 'code' => ' [ '$r===' => '0|1|false', '$matches===' => 'array}>', ], ], 'pregMatchWithFlagUnmatchedAsNull' => [ 'code' => ' [ '$r===' => '0|1|false', '$matches===' => 'array', ], ], 'pregMatchWithFlagOffsetCaptureAndUnmatchedAsNull' => [ 'code' => ' [ '$r===' => '0|1|false', '$matches===' => 'array}>', ], ], 'pregReplaceCallback' => [ 'code' => '\n)/\', /** @param string[] $matches */ function (array $matches) : string { return $matches[1]; }, $s ); }', ], 'pregReplaceCallbackWithArray' => [ 'code' => ' $matches[4], $ids ); };', 'assertions' => [], 'ignored_issues' => [], 'php_version' => '7.4', ], 'compactDefinedVariable' => [ 'code' => ' */ function foo(int $a, string $b, bool $c) : array { return compact("a", "b", "c"); }', ], 'setCookiePhp73' => [ 'code' => ' "/", "expires" => 0, "httponly" => true, "secure" => true, "samesite" => "Lax" ] );', ], 'printrBadArg' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [ '$a' => 'int', ], ], 'callUserFuncArray' => [ 'code' => ' [ '$a' => 'int', ], ], 'dateTest' => [ 'code' => ' [ '$y===' => 'numeric-string', '$ym===' => 'numeric-string', '$y_m===' => 'string', '$m===' => 'numeric-string', '$F===' => 'string', '$y2===' => 'numeric-string', '$F2===' => 'string', '$F3===' => 'string', '$gm_y===' => 'numeric-string', '$gm_ym===' => 'numeric-string', '$gm_m===' => 'numeric-string', '$gm_F===' => 'string', '$gm_y2===' => 'numeric-string', '$gm_F2===' => 'string', '$gm_F3===' => 'string', ], ], 'sscanfReturnTypeWithTwoParameters' => [ 'code' => ' [ '$data' => 'list|null', ], ], 'sscanfReturnTypeWithMoreThanTwoParameters' => [ 'code' => ' [ '$n' => 'int', '$p1' => 'float|int|null|string', '$p2' => 'float|int|null|string', ], ], 'writeArgsAllowed' => [ 'code' => ' [ 'code' => ' [ 'code' => ' $two */ function collectCommit(array $one, array $two) : void { if ($one && array_values($one) === array_values($two)) {} }', ], 'pregMatchAll' => [ 'code' => '> */ function extractUsernames(string $input): array { preg_match_all(\'/([a-zA-Z])*/\', $input, $matches); return $matches; }', ], 'pregMatchAllOffsetCapture' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '7.4', ], 'pregSplit' => [ 'code' => ' [ 'code' => ' */ function foo(string $s) { return preg_split("/ /", $s, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); }', ], 'mbConvertEncodingWithArray' => [ 'code' => ' $str * @return array */ function test2(array $str): array { return mb_convert_encoding($str, "UTF-8", "UTF-8"); }', ], 'getDebugType' => [ 'code' => 'getMessage(); break; } }', 'assertions' => [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'getTypeDoubleThenInt' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'maxWithFloats' => [ 'code' => ' [ 'code' => 'format("Y"); } foo(max(new DateTimeImmutable(), new DateTimeImmutable()));', ], 'maxWithMisc' => [ 'code' => ' [ '$a' => 'DateTimeImmutable|float', ], ], 'maxUnpackArray' => [ 'code' => ' [ 'code' => ' [ '$max===' => '1|2|3|4|DateTime', ], ], 'strtolowerEmptiness' => [ 'code' => ' [ 'code' => ' [ 'code' => ' [ '$s' => 'list', ], 'ignored_issues' => [], 'php_version' => '8.1', ], 'array_is_list_on_empty_array' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.1', ], 'possiblyUndefinedArrayDestructurationOnOptionalArg' => [ 'code' => ' 5) { // when this is done outside if - no errors $arguments[] = new A(); } foo(...$arguments); ', ], 'is_aWithStringableClass' => [ 'code' => ' $exceptionType */ if (\is_a(new Exception(), $exceptionType)) {} ', ], 'strposFirstParamAllowClassString' => [ 'code' => ' [ 'code' => ' [ '$r===' => 'non-empty-string', '$s===' => 'string', '$t===' => 'non-empty-string', '$u===' => 'string', ], ], 'mb_strtolowerProducesLowercaseStringWithNullOrAbsentEncoding' => [ 'code' => ' [ '$a===' => 'non-empty-lowercase-string', '$b===' => 'non-empty-lowercase-string', '$c===' => 'lowercase-string', '$d===' => 'lowercase-string', '$e===' => 'non-empty-lowercase-string', '$f===' => 'non-empty-lowercase-string', '$g===' => 'lowercase-string', '$h===' => 'lowercase-string', ], 'ignored_issues' => [], 'php_version' => '8.1', ], 'count_charsProducesArrayOrString' => [ 'code' => ' [ '$a===' => 'array', '$b===' => 'array', '$c===' => 'array', '$d===' => 'string', '$e===' => 'string', ], 'ignored_issues' => [], 'php_version' => '8.1', ], 'number_formatNamedArgument' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'round_literalValue' => [ 'code' => ' [ '$a===' => 'float(10.36)', ], ], 'allowConstructorAfterEnumExists' => [ 'code' => ' [], 'ignored_issues' => ['MixedMethodCall'], 'php_version' => '8.1', ], 'refineWithEnumExists' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.1', ], 'refineWithClassExistsOrEnumExists' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.1', ], 'trimSavesLowercaseAttribute' => [ 'code' => ' [ '$b===' => 'lowercase-string', ], ], 'ltrimSavesLowercaseAttribute' => [ 'code' => ' [ '$b===' => 'lowercase-string', ], ], 'rtrimSavesLowercaseAttribute' => [ 'code' => ' [ '$b===' => 'lowercase-string', ], ], 'passingStringableObjectToStringableParam' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'passingStringableToStringableObjectParam' => [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'passingImplicitStringableObjectToStringableObjectParam' => [ 'code' => ' [ 'code' => ' [], 'ignored_issues' => [], 'php_version' => '8.0', ], 'noNeverReturnError' => [ 'code' => ' [ 'code' => ' [ 'code' => ' 5 ) { exit; } } ', ], 'getHeadersAssociativeIn8x' => [ 'code' => ' [ '$a' => 'array|string>|false', ], 'ignored_issues' => [], 'php_version' => '8.0', ], 'getHeadersAssociativeIn7x' => [ 'code' => ' [ '$a' => 'false|list', ], 'ignored_issues' => [], 'php_version' => '7.0', ], ]; } public function providerInvalidCodeParse(): iterable { return [ 'invalidScalarArgument' => [ 'code' => ' 'InvalidScalarArgument', ], 'invalidArgumentCallableWithoutArgsUnion' => [ 'code' => ' 'InvalidArgument', ], 'invalidArgumentWithDeclareStrictTypes' => [ 'code' => ' 'InvalidArgument', ], 'invalidArgumentFalseTrueExpected' => [ 'code' => ' 'InvalidArgument', ], 'builtinFunctioninvalidArgumentWithWeakTypes' => [ 'code' => ' 'InvalidScalarArgument', ], 'builtinFunctioninvalidArgumentWithDeclareStrictTypes' => [ 'code' => ' 'InvalidArgument', ], 'builtinFunctioninvalidArgumentWithDeclareStrictTypesInClass' => [ 'code' => ' 'InvalidArgument', ], 'mixedArgument' => [ 'code' => ' 'MixedArgument', 'ignored_issues' => ['MixedAssignment'], ], 'nullArgument' => [ 'code' => ' 'NullArgument', ], 'tooFewArguments' => [ 'code' => ' 'TooFewArguments', ], 'tooManyArguments' => [ 'code' => ' 'TooManyArguments - src' . DIRECTORY_SEPARATOR . 'somefile.php:3:21 - Too many arguments for fooFoo ' . '- expecting 1 but saw 2', ], 'tooManyArgumentsForConstructor' => [ 'code' => ' 'TooManyArguments', ], 'typeCoercion' => [ 'code' => ' 'ArgumentTypeCoercion', ], 'arrayTypeCoercion' => [ 'code' => ' 'ArgumentTypeCoercion', ], 'duplicateParam' => [ 'code' => ' 'DuplicateParam', 'ignored_issues' => ['MissingParamType'], ], 'invalidParamDefault' => [ 'code' => ' 'InvalidParamDefault', ], 'invalidDocblockParamDefault' => [ 'code' => ' 'InvalidParamDefault', ], 'badByRef' => [ 'code' => ' 'InvalidPassByReference', ], 'badArrayByRef' => [ 'code' => ' 'InvalidPassByReference', ], 'invalidArgAfterCallable' => [ 'code' => ' 'InvalidScalarArgument', 'ignored_issues' => [ 'MixedAssignment', 'MixedArrayAccess', 'RedundantConditionGivenDocblockType', ], ], 'undefinedFunctionInArrayMap' => [ 'code' => ' 'UndefinedFunction', ], 'objectLikeKeyChecksAgainstDifferentGeneric' => [ 'code' => ' $b */ function a($b): int { return $b["a"]; } a(["a" => "hello"]);', 'error_message' => 'InvalidArgument', ], 'objectLikeKeyChecksAgainstDifferentTKeyedArray' => [ 'code' => ' "hello"]);', 'error_message' => 'InvalidArgument', ], 'possiblyNullFunctionCall' => [ 'code' => ' 'PossiblyNullFunctionCall', ], 'possiblyInvalidFunctionCall' => [ 'code' => ' 'PossiblyInvalidFunctionCall', ], 'varExportAssignmentToVoid' => [ 'code' => ' 'AssignmentToVoid', ], 'explodeWithEmptyString' => [ 'code' => ' 'InvalidArgument', ], 'complainAboutArrayToIterable' => [ 'code' => ' $p */ function takesIterableOfA(iterable $p): void {} takesIterableOfA([new B]); // should complain', 'error_message' => 'InvalidArgument', ], 'complainAboutArrayToIterableSingleParam' => [ 'code' => ' $p */ function takesIterableOfA(iterable $p): void {} takesIterableOfA([new B]); // should complain', 'error_message' => 'InvalidArgument', ], 'putInvalidTypeMessagesFirst' => [ 'code' => ' 'InvalidArgument', ], 'getTypeInvalidValue' => [ 'code' => ' 'TypeDoesNotContainType', ], 'rangeWithFloatStep' => [ 'code' => ' 'InvalidScalarArgument', ], 'rangeWithFloatStart' => [ 'code' => ' 'InvalidScalarArgument', ], 'duplicateFunction' => [ 'code' => ' 'DuplicateFunction', ], 'duplicateCoreFunction' => [ 'code' => ' 'DuplicateFunction', ], 'functionCallOnMixed' => [ 'code' => ' 'MixedFunctionCall', ], 'iterableOfObjectCannotAcceptIterableOfInt' => [ 'code' => ' $_p */ function accepts(iterable $_p): void {} /** @return iterable */ function iterable() { yield 1; } accepts(iterable());', 'error_message' => 'InvalidArgument', ], 'iterableOfObjectCannotAcceptTraversableOfInt' => [ 'code' => ' $_p */ function accepts(iterable $_p): void {} /** @return Traversable */ function traversable() { yield 1; } accepts(traversable());', 'error_message' => 'InvalidArgument', ], 'iterableOfObjectCannotAcceptGeneratorOfInt' => [ 'code' => ' $_p */ function accepts(iterable $_p): void {} /** @return Generator */ function generator() { yield 1; } accepts(generator());', 'error_message' => 'InvalidArgument', ], 'iterableOfObjectCannotAcceptArrayOfInt' => [ 'code' => ' $_p */ function accepts(iterable $_p): void {} /** @return array */ function arr() { return [1]; } accepts(arr());', 'error_message' => 'InvalidArgument', ], 'nonNullableByRef' => [ 'code' => ' 'NullReference', ], 'intCastByRef' => [ 'code' => ' 'InvalidPassByReference', ], 'implicitAssignmentToStringFromMixed' => [ 'code' => ' 'InvalidScalarArgument', ], 'tooFewArgsAccurateCount' => [ 'code' => ' 'TooFewArguments - src' . DIRECTORY_SEPARATOR . 'somefile.php:2:21 - Too few arguments for preg_match - expecting subject to be passed', ], 'compactUndefinedVariable' => [ 'code' => ' */ function foo() : array { return compact("a", "b", "c"); }', 'error_message' => 'UndefinedVariable', ], 'countCallableArrayShouldBeTwo' => [ 'code' => ' 'TypeDoesNotContainType', ], 'countOnUnknownObjectCannotBePure' => [ 'code' => ' 'ImpureFunctionCall', ], 'coerceCallMapArgsInStrictMode' => [ 'code' => ' 'RedundantCondition', ], 'noCrashOnEmptyArrayPush' => [ 'code' => ' 'TooFewArguments', ], 'printOnlyString' => [ 'code' => ' 'InvalidArgument', ], 'printReturns1' => [ 'code' => ' 'TypeDoesNotContainType', ], 'sodiumMemzeroNullifyString' => [ 'code' => ' 'NullableReturnStatement', ], 'noCrashWithPattern' => [ 'code' => ' 'UndefinedGlobalVariable', ], 'parseUrlPossiblyUndefined' => [ 'code' => ' 'PossiblyUndefinedArrayOffset', ], 'parseUrlPossiblyUndefined2' => [ 'code' => ' 'PossiblyUndefinedArrayOffset', ], 'strposNoSetFirstParam' => [ 'code' => ' 'InvalidLiteralArgument', ], 'curlInitIsResourceFailsIn8x' => [ 'code' => ' 'RedundantCondition', 'ignored_issues' => [], 'php_version' => '8.0', ], 'maxCallWithArray' => [ 'code' => ' 'ArgumentTypeCoercion', ], 'pregSplitNoEmpty' => [ 'code' => ' 'InvalidReturnStatement', ], 'maxWithMixed' => [ 'code' => ' 'MixedAssignment', ], 'literalFalseArgument' => [ 'code' => ' 'InvalidArgument', ], 'getClassWithoutArgsOutsideClass' => [ 'code' => ' 'TooFewArguments', ], 'count_charsWithInvalidMode' => [ 'code' => ' 'ArgumentTypeCoercion', ], 'array_is_list_literal_array' => [ 'code' => ' 0, 0 => 1]; assert(array_is_list($list));', 'error_message' => 'TypeDoesNotContainType', 'ignored_issues' => [], 'php_version' => '8.1', ], 'passingObjectToStringableObjectParam' => [ 'code' => ' 'InvalidArgument', ], 'passingNonStringableObjectToStringableObjectParam' => [ 'code' => ' 'InvalidArgument', ], 'passingStdClassToStringableObjectParam' => [ 'code' => ' 'InvalidArgument', ], 'shouldReturnNeverNotString' => [ 'code' => ' 'InvalidReturnType', ], 'shouldReturnNeverNotStringCaller' => [ 'code' => ' 'InvalidReturnType', ], 'shouldReturnNeverNotStringNoDocblockCaller' => [ 'code' => ' 'InvalidReturnType', ], 'DontAcceptArrayWithShapesNotContained' => [ 'code' => ' $mayBeInt]); ', 'error_message' => 'ArgumentTypeCoercion', ], 'is_a_withAStringAndNoThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAStringAndFalseThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAUnionOfStringsAndNoThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAUnionOfStringsAndFalseThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAClassStringAndNoThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAClassStringAndFalseThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAUnionOfClassStringsAndNoThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'is_a_withAUnionOfClassStringsAndFalseThirdArg' => [ 'code' => ' 'RedundantFunctionCall', ], 'incorrectCallableParamDefault' => [ 'code' => ' 'InvalidParamDefault', ], 'disallowStrposIntSecondParam' => [ 'code' => ' 'InvalidScalarArgument', ], 'disallowNeverTypeForParam' => [ 'code' => ' 'ReservedWord', 'ignored_issues' => [], 'php_version' => '8.1', ], 'extractVarCheckInvalid' => [ 'code' => ' 15]; extract($a); takesInt($foo);', 'error_message' => 'InvalidScalarArgument', ], ]; } public function testTriggerErrorDefault(): void { $config = Config::getInstance(); $config->trigger_error_exits = 'default'; $this->addFile( 'somefile.php', 'assertTrue(true); $this->analyzeFile('somefile.php', new Context()); } public function testTriggerErrorAlways(): void { $config = Config::getInstance(); $config->trigger_error_exits = 'always'; $this->addFile( 'somefile.php', 'assertTrue(true); $this->analyzeFile('somefile.php', new Context()); } public function testTriggerErrorNever(): void { $config = Config::getInstance(); $config->trigger_error_exits = 'never'; $this->addFile( 'somefile.php', 'assertTrue(true); $this->analyzeFile('somefile.php', new Context()); } }