diff --git a/dictionaries/CallMap.php b/dictionaries/CallMap.php index cc88e43fb..1e53b62e2 100644 --- a/dictionaries/CallMap.php +++ b/dictionaries/CallMap.php @@ -3699,7 +3699,7 @@ return [ 'get_defined_functions' => ['array{internal: list, user: list}', 'exclude_disabled='=>'bool'], 'get_defined_vars' => ['array'], 'get_extension_funcs' => ['list|false', 'extension'=>'string'], -'get_headers' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'resource'], +'get_headers' => ['array|false', 'url'=>'string', 'associative='=>'bool', 'context='=>'?resource'], 'get_html_translation_table' => ['array', 'table='=>'int', 'flags='=>'int', 'encoding='=>'string'], 'get_include_path' => ['string'], 'get_included_files' => ['list'], diff --git a/dictionaries/CallMap_71_delta.php b/dictionaries/CallMap_71_delta.php index 84a9e675c..de49f6af6 100644 --- a/dictionaries/CallMap_71_delta.php +++ b/dictionaries/CallMap_71_delta.php @@ -48,7 +48,7 @@ return [ ], 'get_headers' => [ 'old' => ['array|false', 'url'=>'string', 'associative='=>'int'], - 'new' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'resource'], + 'new' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'], ], 'getopt' => [ 'old' => ['array>|false', 'short_options'=>'string', 'long_options='=>'array'], diff --git a/dictionaries/CallMap_80_delta.php b/dictionaries/CallMap_80_delta.php index 0cb1e3726..bfd83a05b 100644 --- a/dictionaries/CallMap_80_delta.php +++ b/dictionaries/CallMap_80_delta.php @@ -673,6 +673,10 @@ return [ 'old' => ['list|null', 'object_or_class'=>'mixed'], 'new' => ['list', 'object_or_class'=>'object|class-string'], ], + 'get_headers' => [ + 'old' => ['array|false', 'url'=>'string', 'associative='=>'int', 'context='=>'?resource'], + 'new' => ['array|false', 'url'=>'string', 'associative='=>'bool', 'context='=>'?resource'], + ], 'get_parent_class' => [ 'old' => ['class-string|false', 'object_or_class='=>'mixed'], 'new' => ['class-string|false', 'object_or_class='=>'object|class-string'], diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php index d6c1c6781..79196cc1d 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/NamedFunctionCallHandler.php @@ -10,6 +10,7 @@ use Psalm\Internal\Analyzer\FunctionLikeAnalyzer; use Psalm\Internal\Analyzer\Statements\Expression\AssertionFinder; use Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier; use Psalm\Internal\Analyzer\Statements\Expression\Fetch\ConstFetchAnalyzer; +use Psalm\Internal\Analyzer\Statements\Expression\IncludeAnalyzer; use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer; use Psalm\Internal\Analyzer\StatementsAnalyzer; use Psalm\Internal\Codebase\VariableUseGraph; @@ -178,6 +179,22 @@ class NamedFunctionCallHandler if ($var_id) { $context->phantom_files[$var_id] = true; + return; + } + + // literal string or (magic) const in file path + $codebase = $statements_analyzer->getCodebase(); + $config = $codebase->config; + $path_to_file = IncludeAnalyzer::getPathTo( + $first_arg->value, + $statements_analyzer->node_data, + $statements_analyzer, + $statements_analyzer->getFileName(), + $config, + ); + + if ($path_to_file) { + $context->phantom_files[$path_to_file] = true; } return; diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php index 0a7af6d59..1b6ad40fd 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/IncludeAnalyzer.php @@ -231,6 +231,15 @@ class IncludeAnalyzer return true; } + if (isset($context->phantom_files[$path_to_file])) { + return true; + } + + $var_id = ExpressionIdentifier::getExtendedVarId($stmt->expr, null); + if ($var_id && isset($context->phantom_files[$var_id])) { + return true; + } + $source = $statements_analyzer->getSource(); IssueBuffer::maybeAdd( diff --git a/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php b/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php index ef659057e..494c888a0 100644 --- a/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php +++ b/src/Psalm/Internal/PhpVisitor/Reflector/FunctionLikeNodeScanner.php @@ -592,11 +592,15 @@ class FunctionLikeNodeScanner $var_comment_readonly = false; $var_comment_allow_private_mutation = false; if ($doc_comment) { + $template_types = ($this->existing_function_template_types ?: []) + + ($classlike_storage->template_types ?: []) + ; + $var_comments = CommentAnalyzer::getTypeFromComment( $doc_comment, $this->file_scanner, $this->aliases, - $this->existing_function_template_types ?: [], + $template_types, $this->type_aliases, ); diff --git a/stubs/CoreGenericFunctions.phpstub b/stubs/CoreGenericFunctions.phpstub index 90355efd5..e5593bdc0 100644 --- a/stubs/CoreGenericFunctions.phpstub +++ b/stubs/CoreGenericFunctions.phpstub @@ -1482,7 +1482,7 @@ function bin2hex(string $string): string {} * * @param resource|null $context * - * @return ($associative is 0 ? list : array>)|false + * @return ($associative is false|0 ? list : array>)|false * * @psalm-taint-sink ssrf $url */ diff --git a/stubs/Php80.phpstub b/stubs/Php80.phpstub index a15ddc82c..3520e1906 100644 --- a/stubs/Php80.phpstub +++ b/stubs/Php80.phpstub @@ -221,3 +221,14 @@ class DatePeriod implements IteratorAggregate /** @psalm-return (Start is string ? (Traversable&Iterator) : (Traversable&Iterator)) */ public function getIterator(): Iterator {} } + +/** + * @psalm-pure + * + * @param resource|null $context + * + * @return ($associative is false|0 ? list : array>)|false + * + * @psalm-taint-sink ssrf $url + */ +function get_headers(string $url, bool $associative = false, $context = null) : array|false {} diff --git a/stubs/extensions/redis.phpstub b/stubs/extensions/redis.phpstub index 0ad1780d2..de8474d47 100644 --- a/stubs/extensions/redis.phpstub +++ b/stubs/extensions/redis.phpstub @@ -1,554 +1,556 @@ |Redis */ - public function mget(array $keys); + public function mget(array $keys) {} - public function migrate(string $host, int $port, string $key, string $dst, int $timeout, bool $copy = false, bool $replace = false): bool; + public function migrate(string $host, int $port, string $key, string $dst, int $timeout, bool $copy = false, bool $replace = false): bool {} - public function move(string $key, int $index): bool; + public function move(string $key, int $index): bool {} /** * @param array */ - public function mset($key_values): Redis|bool; + public function mset($key_values): Redis|bool {} /** * @param array */ - public function msetnx($key_values): Redis|bool; + public function msetnx($key_values): Redis|bool {} - public function multi(int $value = Redis::MULTI): bool|Redis; + public function multi(int $value = Redis::MULTI): bool|Redis {} - public function object(string $subcommand, string $key): Redis|int|string|false; + public function object(string $subcommand, string $key): Redis|int|string|false {} /** * @deprecated * @alias Redis::connect */ - public function open(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool; + public function open(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool {} - public function pconnect(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool; + public function pconnect(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool {} -public function persist(string $key): bool; + public function persist(string $key): bool {} - public function pexpire(string $key, int $timeout): bool; + public function pexpire(string $key, int $timeout): bool {} - public function pexpireAt(string $key, int $timestamp): bool; + public function pexpireAt(string $key, int $timestamp): bool {} - public function pfadd(string $key, array $elements): int; + public function pfadd(string $key, array $elements): int {} - public function pfcount(string $key): int; + public function pfcount(string $key): int {} - public function pfmerge(string $dst, array $keys): bool; + public function pfmerge(string $dst, array $keys): bool {} /** @return false|string|Redis */ - public function ping(string $key = NULL); + public function ping(string $key = NULL) {} - public function pipeline(): bool|Redis; + public function pipeline(): bool|Redis {} /** * @deprecated * @alias Redis::pconnect */ - public function popen(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool; + public function popen(string $host, int $port = 6379, float $timeout = 0, string $persistent_id = NULL, int $retry_interval = 0, float $read_timeout = 0, array $context = NULL): bool {} /** @return bool|Redis */ - public function psetex(string $key, int $expire, string $value); + public function psetex(string $key, int $expire, string $value) {} - public function psubscribe(array $patterns): void; + public function psubscribe(array $patterns): void {} - public function pttl(string $key): Redis|int|false; + public function pttl(string $key): Redis|int|false {} - public function publish(string $channel, string $message): mixed; + public function publish(string $channel, string $message): mixed {} - public function pubsub(string $command, mixed $arg = null): mixed; + public function pubsub(string $command, mixed $arg = null): mixed {} - public function punsubscribe(array $patterns): array|false; + public function punsubscribe(array $patterns): array|false {} /** @return false|string|Redis */ - public function rPop(string $key); + public function rPop(string $key) {} /** @return false|string|Redis */ - public function randomKey(); + public function randomKey() {} - public function rawcommand(string $command, mixed ...$args): mixed; + public function rawcommand(string $command, mixed ...$args): mixed {} /** @return bool|Redis */ - public function rename(string $key_src, string $key_dst); + public function rename(string $key_src, string $key_dst) {} /** @return bool|Redis */ - public function renameNx(string $key_src, string $key_dst); + public function renameNx(string $key_src, string $key_dst) {} - public function restore(string $key, int $timeout, string $value): bool; + public function restore(string $key, int $timeout, string $value): bool {} - public function role(): mixed; + public function role(): mixed {} - public function rpoplpush(string $src, string $dst): Redis|string|false; + public function rpoplpush(string $src, string $dst): Redis|string|false {} - public function sAdd(string $key, string $value, mixed ...$other_values): Redis|int|false; + public function sAdd(string $key, string $value, mixed ...$other_values): Redis|int|false {} - public function sAddArray(string $key, array $values): int; + public function sAddArray(string $key, array $values): int {} - public function sDiff(string $key, string ...$other_keys): Redis|array|false; + public function sDiff(string $key, string ...$other_keys): Redis|array|false {} - public function sDiffStore(string $dst, string $key, string ...$other_keys): Redis|int|false; + public function sDiffStore(string $dst, string $key, string ...$other_keys): Redis|int|false {} - public function sInter(array|string $key, string ...$other_keys): Redis|array|false; + public function sInter(array|string $key, string ...$other_keys): Redis|array|false {} - public function sInterStore(array|string $key, string ...$other_keys): Redis|int|false; + public function sInterStore(array|string $key, string ...$other_keys): Redis|int|false {} - public function sMembers(string $key): Redis|array|false; + public function sMembers(string $key): Redis|array|false {} - public function sMisMember(string $key, string $member, string ...$other_members): array|false; + public function sMisMember(string $key, string $member, string ...$other_members): array|false {} - public function sMove(string $src, string $dst, string $value): Redis|bool; + public function sMove(string $src, string $dst, string $value): Redis|bool {} - public function sPop(string $key, int $count = 0): Redis|string|array|false; + public function sPop(string $key, int $count = 0): Redis|string|array|false {} - public function sRandMember(string $key, int $count = 0): Redis|string|array|false; + public function sRandMember(string $key, int $count = 0): Redis|string|array|false {} - public function sUnion(string $key, string ...$other_keys): Redis|array|false; + public function sUnion(string $key, string ...$other_keys): Redis|array|false {} - public function sUnionStore(string $dst, string $key, string ...$other_keys): Redis|int|false; + public function sUnionStore(string $dst, string $key, string ...$other_keys): Redis|int|false {} - public function save(): bool; + public function save(): bool {} - public function scan(?int &$iterator, ?string $pattern = null, int $count = 0, string $type = NULL): array|false; + public function scan(?int &$iterator, ?string $pattern = null, int $count = 0, string $type = NULL): array|false {} - public function scard(string $key): Redis|int|false; + public function scard(string $key): Redis|int|false {} - public function script(string $command, mixed ...$args): mixed; + public function script(string $command, mixed ...$args): mixed {} - public function select(int $db): bool; + public function select(int $db): bool {} /** @return bool|Redis */ - public function set(string $key, string $value, mixed $opt = NULL); + public function set(string $key, string $value, mixed $opt = NULL) {} /** @return false|int|Redis */ - public function setBit(string $key, int $idx, bool $value); + public function setBit(string $key, int $idx, bool $value) {} /** @return false|int|Redis */ - public function setRange(string $key, int $start, string $value); + public function setRange(string $key, int $start, string $value) {} - public function setOption(int $option, mixed $value): bool; + public function setOption(int $option, mixed $value): bool {} /** @return bool|Redis */ - public function setex(string $key, int $expire, string $value); + public function setex(string $key, int $expire, string $value) {} /** @return bool|array|Redis */ - public function setnx(string $key, string $value); + public function setnx(string $key, string $value) {} - public function sismember(string $key, string $value): Redis|bool; + public function sismember(string $key, string $value): Redis|bool {} - public function slaveof(string $host = null, int $port = 6379): bool; + public function slaveof(string $host = null, int $port = 6379): bool {} - public function slowlog(string $mode, int $option = 0): mixed; + public function slowlog(string $mode, int $option = 0): mixed {} - public function sort(string $key, array $options = null): mixed; + public function sort(string $key, array $options = null): mixed {} /** * @deprecated */ - public function sortAsc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array; + public function sortAsc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {} /** * @deprecated */ - public function sortAscAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array; + public function sortAscAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {} /** * @deprecated */ - public function sortDesc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array; + public function sortDesc(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {} /** * @deprecated */ - public function sortDescAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array; + public function sortDescAlpha(string $key, ?string $pattern = null, mixed $get = null, int $offset = -1, int $count = -1, ?string $store = null): array {} - public function srem(string $key, string $value, mixed ...$other_values): Redis|int|false; + public function srem(string $key, string $value, mixed ...$other_values): Redis|int|false {} - public function sscan(string $key, int &$iterator, ?string $pattern = null, int $count = 0): array|false; + public function sscan(string $key, int &$iterator, ?string $pattern = null, int $count = 0): array|false {} /** @return false|int|Redis */ - public function strlen(string $key); + public function strlen(string $key) {} - public function subscribe(string $channel, string ...$other_channels): array|false; + public function subscribe(string $channel, string ...$other_channels): array|false {} - public function swapdb(string $src, string $dst): bool; + public function swapdb(string $src, string $dst): bool {} - public function time(): array|false; + public function time(): array|false {} - public function ttl(string $key): Redis|int|false; + public function ttl(string $key): Redis|int|false {} /** @return false|int|Redis */ - public function type(string $key); + public function type(string $key) {} /** * @return false|int|Redis */ - public function unlink(array|string $key, string ...$other_keys); + public function unlink(array|string $key, string ...$other_keys) {} - public function unsubscribe(string $channel, string ...$other_channels): array|false; + public function unsubscribe(string $channel, string ...$other_channels): array|false {} /** @return bool|Redis */ - public function unwatch(); + public function unwatch() {} /** * @return bool|Redis */ - public function watch(array|string $key, string ...$other_keys); + public function watch(array|string $key, string ...$other_keys) {} - public function wait(int $count, int $timeout): int|false; + public function wait(int $count, int $timeout): int|false {} - public function xack(string $key, string $group, array $ids): int|false; + public function xack(string $key, string $group, array $ids): int|false {} - public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false): string|false; + public function xadd(string $key, string $id, array $values, int $maxlen = 0, bool $approx = false): string|false {} - public function xclaim(string $key, string $group, string $consumer, int $min_iddle, array $ids, array $options): string|array|false; + public function xclaim(string $key, string $group, string $consumer, int $min_iddle, array $ids, array $options): string|array|false {} - public function xdel(string $key, array $ids): Redis|int|false; + public function xdel(string $key, array $ids): Redis|int|false {} - public function xgroup(string $operation, string $key = null, string $arg1 = null, string $arg2 = null, bool $arg3 = false): mixed; + public function xgroup(string $operation, string $key = null, string $arg1 = null, string $arg2 = null, bool $arg3 = false): mixed {} - public function xinfo(string $operation, ?string $arg1 = null, ?string $arg2 = null, int $count = -1): mixed; + public function xinfo(string $operation, ?string $arg1 = null, ?string $arg2 = null, int $count = -1): mixed {} - public function xlen(string $key): int; + public function xlen(string $key): int {} - public function xpending(string $key, string $group, string $start = null, string $end = null, int $count = -1, string $consumer = null): Redis|array|false; + public function xpending(string $key, string $group, string $start = null, string $end = null, int $count = -1, string $consumer = null): Redis|array|false {} - public function xrange(string $key, string $start, string $end, int $count = -1): bool|array; + public function xrange(string $key, string $start, string $end, int $count = -1): bool|array {} - public function xread(array $streams, int $count = -1, int $block = -1): bool|array; + public function xread(array $streams, int $count = -1, int $block = -1): bool|array {} - public function xreadgroup(string $group, string $consumer, array $streams, int $count = 1, int $block = 1): bool|array; + public function xreadgroup(string $group, string $consumer, array $streams, int $count = 1, int $block = 1): bool|array {} - public function xrevrange(string $key, string $start, string $end, int $count = -1): bool|array; + public function xrevrange(string $key, string $start, string $end, int $count = -1): bool|array {} - public function xtrim(string $key, int $maxlen, bool $approx = false): int; + public function xtrim(string $key, int $maxlen, bool $approx = false): int {} - public function zAdd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): Redis|int|false; + public function zAdd(string $key, array|float $score_or_options, mixed ...$more_scores_and_mems): Redis|int|false {} - public function zCard(string $key): Redis|int|false; + public function zCard(string $key): Redis|int|false {} - public function zCount(string $key, string $start , string $end): Redis|int|false; + public function zCount(string $key, string $start , string $end): Redis|int|false {} - public function zIncrBy(string $key, float $value, mixed $member): Redis|float|false; + public function zIncrBy(string $key, float $value, mixed $member): Redis|float|false {} - public function zLexCount(string $key, string $min, string $max): Redis|int|false; + public function zLexCount(string $key, string $min, string $max): Redis|int|false {} - public function zMscore(string $key, string $member, string ...$other_members): array|false; + public function zMscore(string $key, string $member, string ...$other_members): array|false {} - public function zPopMax(string $key, int $value = null): array|false; + public function zPopMax(string $key, int $value = null): array|false {} - public function zPopMin(string $key, int $value = null): array|false; + public function zPopMin(string $key, int $value = null): array|false {} - public function zRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false; + public function zRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false {} - public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false; + public function zRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false {} - public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false; + public function zRangeByScore(string $key, string $start, string $end, array $options = []): Redis|array|false {} - public function zRandMember(string $key, array $options = null): string|array|false; + public function zRandMember(string $key, array $options = null): string|array|false {} - public function zRank(string $key, mixed $member): Redis|int|false; + public function zRank(string $key, mixed $member): Redis|int|false {} - public function zRem(mixed $key, mixed $member, mixed ...$other_members): Redis|int|false; + public function zRem(mixed $key, mixed $member, mixed ...$other_members): Redis|int|false {} - public function zRemRangeByLex(string $key, string $min, string $max): int|false; + public function zRemRangeByLex(string $key, string $min, string $max): int|false {} - public function zRemRangeByRank(string $key, int $start, int $end): Redis|int|false; + public function zRemRangeByRank(string $key, int $start, int $end): Redis|int|false {} - public function zRemRangeByScore(string $key, string $start, string $end): Redis|int|false; + public function zRemRangeByScore(string $key, string $start, string $end): Redis|int|false {} - public function zRevRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false; + public function zRevRange(string $key, int $start, int $end, mixed $scores = null): Redis|array|false {} - public function zRevRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false; + public function zRevRangeByLex(string $key, string $min, string $max, int $offset = -1, int $count = -1): array|false {} - public function zRevRangeByScore(string $key, string $start, string $end, array $options = []): array|false; + public function zRevRangeByScore(string $key, string $start, string $end, array $options = []): array|false {} - public function zRevRank(string $key, mixed $member): Redis|int|false; + public function zRevRank(string $key, mixed $member): Redis|int|false {} - public function zScore(string $key, mixed $member): Redis|float|false; + public function zScore(string $key, mixed $member): Redis|float|false {} - public function zdiff(array $keys, array $options = null): array|false; + public function zdiff(array $keys, array $options = null): array|false {} - public function zdiffstore(string $dst, array $keys, array $options = null): int; + public function zdiffstore(string $dst, array $keys, array $options = null): int {} - public function zinter(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false; + public function zinter(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false {} - public function zinterstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): Redis|int|false; + public function zinterstore(string $dst, array $keys, ?array $weights = null, ?string $aggregate = null): Redis|int|false {} - public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array; + public function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): bool|array {} - public function zunion(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false; + public function zunion(array $keys, ?array $weights = null, ?array $options = null): Redis|array|false {} - public function zunionstore(string $dst, array $keys, ?array $weights = NULL, ?string $aggregate = NULL): Redis|int|false; + public function zunionstore(string $dst, array $keys, ?array $weights = NULL, ?string $aggregate = NULL): Redis|int|false {} } diff --git a/tests/FunctionCallTest.php b/tests/FunctionCallTest.php index d1960c3b6..41916337e 100644 --- a/tests/FunctionCallTest.php +++ b/tests/FunctionCallTest.php @@ -2045,6 +2045,24 @@ class FunctionCallTest extends TestCase } ', ], + 'getHeadersAssociativeIn8x' => [ + 'code' => ' [ + '$a' => 'array|string>|false', + ], + 'ignored_issues' => [], + 'php_version' => '8.0', + ], + 'getHeadersAssociativeIn7x' => [ + 'code' => ' [ + '$a' => 'false|list', + ], + 'ignored_issues' => [], + 'php_version' => '7.0', + ], ]; } diff --git a/tests/Internal/Codebase/InternalCallMapHandlerTest.php b/tests/Internal/Codebase/InternalCallMapHandlerTest.php index b41ce65fb..5a9e5a28a 100644 --- a/tests/Internal/Codebase/InternalCallMapHandlerTest.php +++ b/tests/Internal/Codebase/InternalCallMapHandlerTest.php @@ -211,7 +211,6 @@ class InternalCallMapHandlerTest extends TestCase 'finfo::file', 'finfo::set_flags', 'generator::throw', - 'get_headers', 'globiterator::__construct', 'globiterator::getfileinfo', 'globiterator::getpathinfo', diff --git a/tests/Template/ClassTemplateTest.php b/tests/Template/ClassTemplateTest.php index 68a099ab2..4105b6dfb 100644 --- a/tests/Template/ClassTemplateTest.php +++ b/tests/Template/ClassTemplateTest.php @@ -4029,6 +4029,28 @@ class ClassTemplateTest extends TestCase $baz = new DoesNotExist(); foobar($baz);', ], + 'promoted property with template' => [ + 'code' => 't; + ', + 'assertions' => [ + '$a' => 'A', + '$t' => 'int', + ], + 'ignored_issues' => [], + 'php_version' => '8.0', + ], ]; }