From d36abfb98f74c27dba265781e2d14694efd985b8 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sun, 10 Aug 2025 12:21:54 +0200 Subject: [PATCH] Declare assert-if-true for filesystem functions --- conf/config.neon | 1 + stubs/file.stub | 190 +++++++++++++++++ .../nsrt/non-empty-string-file-functions.php | 194 ++++++++++++++++++ ...mpossibleCheckTypeFunctionCallRuleTest.php | 6 + .../Rules/Comparison/data/bug-6788.php | 19 ++ 5 files changed, 410 insertions(+) create mode 100644 stubs/file.stub create mode 100644 tests/PHPStan/Analyser/nsrt/non-empty-string-file-functions.php create mode 100644 tests/PHPStan/Rules/Comparison/data/bug-6788.php diff --git a/conf/config.neon b/conf/config.neon index 664145f443..c8bfcb90dc 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -127,6 +127,7 @@ parameters: - ../stubs/core.stub - ../stubs/typeCheckingFunctions.stub - ../stubs/Countable.stub + - ../stubs/file.stub earlyTerminatingMethodCalls: [] earlyTerminatingFunctionCalls: [] resultCachePath: %tmpDir%/resultCache.php diff --git a/stubs/file.stub b/stubs/file.stub new file mode 100644 index 0000000000..48abcade87 --- /dev/null +++ b/stubs/file.stub @@ -0,0 +1,190 @@ +|false + */ +function scandir(string $directory, int $sorting_order = 0, $context = null) {} + +/** + * @phpstan-assert-if-true =non-empty-string $filename + */ +function is_writable(string $filename): bool {} + +/** + * @phpstan-assert-if-true =non-empty-string $filename + */ +function is_readable(string $filename): bool {} + +/** + * @phpstan-assert-if-true =non-empty-string $filename + */ +function is_executable(string $filename): bool {} + +/** + * @param ?resource $context + * @phpstan-assert-if-true =non-empty-string $filename + * @return list|false + */ +function file(string $filename, int $flags = 0, $context = null) {} + +/** + * @param ?resource $context + * @return string|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function file_get_contents(string $filename, bool $use_include_path = false, $context = null, int $offset = 0, ?int $length = null) {} + +/** + * @param ?resource $context + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function file_put_contents(string $filename, mixed $data, int $flags = 0, $context = null) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function fileatime(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function filectime(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function filegroup(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function fileinode(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function filemtime(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function fileowner(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function fileperms(string $filename) {} + +/** + * @return 0|positive-int|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function filesize(string $filename) {} + +/** + * @return string|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function filetype(string $filename) {} + +/** + * @param ?resource $context + * @return resource|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function fopen(string $filename, string $mode, bool $use_include_path = false, $context = null) {} + +/** + * @return int|false + * @phpstan-assert-if-true =non-empty-string $path + */ +function linkinfo(string $path) {} + +/** + * @return array|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function lstat(string $filename) {} + +/** + * @param ?resource $context + * @phpstan-assert-if-true =non-empty-string $directory + */ +function mkdir(string $directory, int $permissions = 0777, bool $recursive = false, $context = null): bool {} + +/** + * @return 0|positive-int|false + * @param ?resource $context + * @phpstan-assert-if-true =non-empty-string $filename + */ +function readfile(string $filename, bool $use_include_path = false, $context = null) {} + +/** + * @return non-empty-string|false + * @phpstan-assert-if-true =non-empty-string $path + */ +function readlink(string $path) {} + +/** + * @return non-empty-string|false + * @phpstan-assert-if-true =non-empty-string $path + */ +function realpath(string $path) {} + +/** + * @param ?resource $context + * @phpstan-assert-if-true =non-empty-string $directory + */ +function rmdir(string $directory, $context): bool {} + +/** + * @return array|false + * @phpstan-assert-if-true =non-empty-string $filename + */ +function stat(string $filename) {} + +/** + * @phpstan-assert-if-true =non-empty-string $filename + */ +function touch(string $filename, ?int $mtime, ?int $atime): bool {} + +/** + * @param ?resource $context + * @phpstan-assert-if-true =non-empty-string $filename + */ +function unlink(string $filename, $context = null): bool {} + diff --git a/tests/PHPStan/Analyser/nsrt/non-empty-string-file-functions.php b/tests/PHPStan/Analyser/nsrt/non-empty-string-file-functions.php new file mode 100644 index 0000000000..794a17316b --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/non-empty-string-file-functions.php @@ -0,0 +1,194 @@ +analyse([__DIR__ . '/data/bug-13291.php'], []); } + public function testBug6788(): void + { + $this->treatPhpDocTypesAsCertain = true; + $this->analyse([__DIR__ . '/data/bug-6788.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Comparison/data/bug-6788.php b/tests/PHPStan/Rules/Comparison/data/bug-6788.php new file mode 100644 index 0000000000..5be7e4bed2 --- /dev/null +++ b/tests/PHPStan/Rules/Comparison/data/bug-6788.php @@ -0,0 +1,19 @@ +