Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Glob return type stub #9878

Merged
merged 3 commits into from Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion dictionaries/CallMap.php
Expand Up @@ -3330,7 +3330,7 @@
'gettimeofday' => ['array<string, int>'],
'gettimeofday\'1' => ['float', 'as_float='=>'true'],
'gettype' => ['string', 'value'=>'mixed'],
'glob' => ['list<non-empty-string>|false', 'pattern'=>'string', 'flags='=>'int<1, max>'],
'glob' => ['false|list{0?:string, ...<non-empty-string>}', 'pattern'=>'string', 'flags='=>'int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOCHECK, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ONLYDIR, GLOB_ERR>'],
'GlobIterator::__construct' => ['void', 'pattern'=>'string', 'flags='=>'int'],
'GlobIterator::count' => ['int'],
'GlobIterator::current' => ['FilesystemIterator|SplFileInfo|string'],
Expand Down
2 changes: 1 addition & 1 deletion dictionaries/CallMap_historical.php
Expand Up @@ -10728,7 +10728,7 @@
'gettimeofday' => ['array<string, int>'],
'gettimeofday\'1' => ['float', 'as_float='=>'true'],
'gettype' => ['string', 'value'=>'mixed'],
'glob' => ['list<non-empty-string>|false', 'pattern'=>'string', 'flags='=>'int<1, max>'],
'glob' => ['false|list{0?:string, ...<non-empty-string>}', 'pattern'=>'string', 'flags='=>'int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOCHECK, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ONLYDIR, GLOB_ERR>'],
'gmdate' => ['string', 'format'=>'string', 'timestamp='=>'int'],
'gmmktime' => ['int|false', 'hour='=>'int', 'minute='=>'int', 'second='=>'int', 'month='=>'int', 'day='=>'int', 'year='=>'int'],
'gmp_abs' => ['GMP', 'num'=>'GMP|string|int'],
Expand Down
29 changes: 29 additions & 0 deletions stubs/CoreGenericFunctions.phpstub
Expand Up @@ -1709,3 +1709,32 @@ function pg_escape_literal($string1, $string2 = null) {}
* @psalm-flow ($string1, $string2) -> return
*/
function pg_escape_string($string1, $string2 = null) {}

/**
* @psalm-template P of string
* @psalm-template F of int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOCHECK, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ONLYDIR, GLOB_ERR>
* @psalm-param P $pattern
* @psalm-param F $flags
* @psalm-return (
* P is ''
* ? (F is int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ONLYDIR, GLOB_ERR>
* ? false|list<never>
* : (F is int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOCHECK, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ERR>
* ? false|list{0:''}
* : false|list<never>
* )
* )
* : (F is int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ONLYDIR, GLOB_ERR>
* ? false|list<non-empty-string>
* : (F is int-mask<GLOB_MARK, GLOB_NOSORT, GLOB_NOCHECK, GLOB_NOESCAPE, GLOB_BRACE, GLOB_ERR>
* ? false|list{0:non-empty-string, ...<non-empty-string>}
* : false|list<non-empty-string>
* )
* )
* )
* @psalm-ignore-falsable-return
*/
function glob (string $pattern, int $flags = 0): array|false {}



113 changes: 113 additions & 0 deletions tests/CoreStubsTest.php
Expand Up @@ -293,6 +293,119 @@ function after_str_ends_with()
echo str_contains($d, "psalm");
',
];
yield 'glob return types' => [
'code' => <<<'PHP'
<?php
/** @var int-mask<GLOB_NOCHECK> */
$maybeNocheckFlag = 0;
/** @var int-mask<GLOB_ONLYDIR> */
$maybeOnlydirFlag = 0;

/** @var string */
$string = '';

$emptyPatternNoFlags = glob( '' );
$emptyPatternWithoutNocheckFlag1 = glob( '', GLOB_MARK );
$emptyPatternWithoutNocheckFlag2 = glob( '' , GLOB_NOSORT | GLOB_NOESCAPE);
$emptyPatternWithoutNocheckFlag3 = glob( '' , GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ONLYDIR | GLOB_ERR);
$emptyPatternWithNocheckFlag1 = glob( '' , GLOB_NOCHECK);
$emptyPatternWithNocheckFlag2 = glob( '' , GLOB_NOCHECK | GLOB_MARK);
$emptyPatternWithNocheckFlag3 = glob( '' , GLOB_NOCHECK | GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ERR);
$emptyPatternWithNocheckAndOnlydirFlag1 = glob( '' , GLOB_NOCHECK | GLOB_ONLYDIR);
$emptyPatternWithNocheckAndOnlydirFlag2 = glob( '' , GLOB_NOCHECK | GLOB_ONLYDIR | GLOB_MARK);
$emptyPatternWithNocheckAndOnlydirFlag3 = glob( '' , GLOB_NOCHECK | GLOB_ONLYDIR | GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ERR);
$emptyPatternWithNocheckFlagAndMaybeOnlydir = glob( '' , GLOB_NOCHECK | $maybeOnlydirFlag);
$emptyPatternMaybeWithNocheckFlag = glob( '' , $maybeNocheckFlag);
$emptyPatternMaybeWithNocheckFlagAndOnlydir = glob( '' , $maybeNocheckFlag | GLOB_ONLYDIR);
$emptyPatternMaybeWithNocheckFlagAndMaybeOnlydir = glob( '' , $maybeNocheckFlag | $maybeOnlydirFlag);

$nonEmptyPatternNoFlags = glob( 'pattern' );
$nonEmptyPatternWithoutNocheckFlag1 = glob( 'pattern', GLOB_MARK );
$nonEmptyPatternWithoutNocheckFlag2 = glob( 'pattern' , GLOB_NOSORT | GLOB_NOESCAPE);
$nonEmptyPatternWithoutNocheckFlag3 = glob( 'pattern' , GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ONLYDIR | GLOB_ERR);
$nonEmptyPatternWithNocheckFlag1 = glob( 'pattern' , GLOB_NOCHECK);
$nonEmptyPatternWithNocheckFlag2 = glob( 'pattern' , GLOB_NOCHECK | GLOB_MARK);
$nonEmptyPatternWithNocheckFlag3 = glob( 'pattern' , GLOB_NOCHECK | GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ERR);
$nonEmptyPatternWithNocheckAndOnlydirFlag1 = glob( 'pattern' , GLOB_NOCHECK | GLOB_ONLYDIR);
$nonEmptyPatternWithNocheckAndOnlydirFlag2 = glob( 'pattern' , GLOB_NOCHECK | GLOB_ONLYDIR | GLOB_MARK);
$nonEmptyPatternWithNocheckAndOnlydirFlag3 = glob( 'pattern' , GLOB_NOCHECK | GLOB_ONLYDIR | GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ERR);
$nonEmptyPatternWithNocheckFlagAndMaybeOnlydir = glob( 'pattern' , GLOB_NOCHECK | $maybeOnlydirFlag);
$nonEmptyPatternMaybeWithNocheckFlag = glob( 'pattern' , $maybeNocheckFlag);
$nonEmptyPatternMaybeWithNocheckFlagAndOnlydir = glob( 'pattern' , $maybeNocheckFlag | GLOB_ONLYDIR);
$nonEmptyPatternMaybeWithNocheckFlagAndMaybeOnlydir = glob( 'pattern' , $maybeNocheckFlag | $maybeOnlydirFlag);

$stringPatternNoFlags = glob( $string );
$stringPatternWithoutNocheckFlag1 = glob( $string, GLOB_MARK );
$stringPatternWithoutNocheckFlag2 = glob( $string , GLOB_NOSORT | GLOB_NOESCAPE);
$stringPatternWithoutNocheckFlag3 = glob( $string , GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ONLYDIR | GLOB_ERR);
$stringPatternWithNocheckFlag1 = glob( $string , GLOB_NOCHECK);
$stringPatternWithNocheckFlag2 = glob( $string , GLOB_NOCHECK | GLOB_MARK);
$stringPatternWithNocheckFlag3 = glob( $string , GLOB_NOCHECK | GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ERR);
$stringPatternWithNocheckAndOnlydirFlag1 = glob( $string , GLOB_NOCHECK | GLOB_ONLYDIR);
$stringPatternWithNocheckAndOnlydirFlag2 = glob( $string , GLOB_NOCHECK | GLOB_ONLYDIR | GLOB_MARK);
$stringPatternWithNocheckAndOnlydirFlag3 = glob( $string , GLOB_NOCHECK | GLOB_ONLYDIR | GLOB_MARK | GLOB_NOSORT | GLOB_NOESCAPE | GLOB_BRACE | GLOB_ERR);
$stringPatternWithNocheckFlagAndMaybeOnlydir = glob( $string , GLOB_NOCHECK | $maybeOnlydirFlag);
$stringPatternMaybeWithNocheckFlag = glob( $string , $maybeNocheckFlag);
$stringPatternMaybeWithNocheckFlagAndOnlydir = glob( $string , $maybeNocheckFlag | GLOB_ONLYDIR);
$stringPatternMaybeWithNocheckFlagAndMaybeOnlydir = glob( $string , $maybeNocheckFlag | $maybeOnlydirFlag);
PHP,
'assertions' => [
'$emptyPatternNoFlags===' => 'false|list<never>',
'$emptyPatternWithoutNocheckFlag1===' => 'false|list<never>',
'$emptyPatternWithoutNocheckFlag2===' => 'false|list<never>',
'$emptyPatternWithoutNocheckFlag3===' => 'false|list<never>',
'$emptyPatternWithNocheckFlag1===' => 'false|list{\'\'}',
'$emptyPatternWithNocheckFlag2===' => 'false|list{\'\'}',
'$emptyPatternWithNocheckFlag3===' => 'false|list{\'\'}',
'$emptyPatternWithNocheckAndOnlydirFlag1===' => 'false|list<never>',
'$emptyPatternWithNocheckAndOnlydirFlag2===' => 'false|list<never>',
'$emptyPatternWithNocheckAndOnlydirFlag3===' => 'false|list<never>',
'$emptyPatternWithNocheckFlagAndMaybeOnlydir===' => 'false|list{0?: \'\', ...<never>}',
'$emptyPatternMaybeWithNocheckFlag===' => 'false|list{0?: \'\', ...<never>}',
'$emptyPatternMaybeWithNocheckFlagAndOnlydir===' => 'false|list<never>',
'$emptyPatternMaybeWithNocheckFlagAndMaybeOnlydir===' => 'false|list{0?: \'\', ...<never>}',

'$nonEmptyPatternNoFlags===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithoutNocheckFlag1===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithoutNocheckFlag2===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithoutNocheckFlag3===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithNocheckFlag1===' => 'false|non-empty-list<non-empty-string>',
'$nonEmptyPatternWithNocheckFlag2===' => 'false|non-empty-list<non-empty-string>',
'$nonEmptyPatternWithNocheckFlag3===' => 'false|non-empty-list<non-empty-string>',
'$nonEmptyPatternWithNocheckAndOnlydirFlag1===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithNocheckAndOnlydirFlag2===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithNocheckAndOnlydirFlag3===' => 'false|list<non-empty-string>',
'$nonEmptyPatternWithNocheckFlagAndMaybeOnlydir===' => 'false|list<non-empty-string>',
'$nonEmptyPatternMaybeWithNocheckFlag===' => 'false|list<non-empty-string>',
'$nonEmptyPatternMaybeWithNocheckFlagAndOnlydir===' => 'false|list<non-empty-string>',
'$nonEmptyPatternMaybeWithNocheckFlagAndMaybeOnlydir===' => 'false|list<non-empty-string>',

'$stringPatternNoFlags===' => 'false|list<non-empty-string>',
'$stringPatternWithoutNocheckFlag1===' => 'false|list<non-empty-string>',
'$stringPatternWithoutNocheckFlag2===' => 'false|list<non-empty-string>',
'$stringPatternWithoutNocheckFlag3===' => 'false|list<non-empty-string>',
'$stringPatternWithNocheckFlag1===' => 'false|list{string, ...<non-empty-string>}',
'$stringPatternWithNocheckFlag2===' => 'false|list{string, ...<non-empty-string>}',
'$stringPatternWithNocheckFlag3===' => 'false|list{string, ...<non-empty-string>}',
'$stringPatternWithNocheckAndOnlydirFlag1===' => 'false|list<non-empty-string>',
'$stringPatternWithNocheckAndOnlydirFlag2===' => 'false|list<non-empty-string>',
'$stringPatternWithNocheckAndOnlydirFlag3===' => 'false|list<non-empty-string>',
'$stringPatternWithNocheckFlagAndMaybeOnlydir===' => 'false|list{0?: string, ...<non-empty-string>}',
'$stringPatternMaybeWithNocheckFlag===' => 'false|list{0?: string, ...<non-empty-string>}',
'$stringPatternMaybeWithNocheckFlagAndOnlydir===' => 'false|list<non-empty-string>',
'$stringPatternMaybeWithNocheckFlagAndMaybeOnlydir===' => 'false|list{0?: string, ...<non-empty-string>}',
],
];
yield 'glob return ignores false' => [
'code' => <<<'PHP'
<?php
/**
* @param list $list
*/
function takesList(array $list): void {}
takesList(glob( '' ));
PHP,
];
}

public function providerInvalidCodeParse(): iterable
Expand Down