diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9d4f275e4..61f8d7679 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -568,8 +568,6 @@ $const_name - $type[0] - $type[0][0] diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index cca108354..4ed538975 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -2238,6 +2238,10 @@ class Config $stubsDir . 'SPL.phpstub', ]; + if ($codebase->analysis_php_version_id >= 7_04_00) { + $this->internal_stubs[] = $stubsDir . 'Php74.phpstub'; + } + if ($codebase->analysis_php_version_id >= 8_00_00) { $this->internal_stubs[] = $stubsDir . 'CoreGenericAttributes.phpstub'; $this->internal_stubs[] = $stubsDir . 'Php80.phpstub'; diff --git a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php index a418a52bc..6be055ea4 100644 --- a/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php @@ -200,6 +200,10 @@ class ProjectAnalyzer UnnecessaryVarAnnotation::class, ]; + private const PHP_VERSION_REGEX = '^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\..*)?$'; + + private const PHP_SUPPORTED_VERSIONS_REGEX = '^(5\.[456]|7\.[01234]|8\.[0123])(\..*)?$'; + /** * @param array $generated_report_options */ @@ -1179,8 +1183,16 @@ class ProjectAnalyzer */ public function setPhpVersion(string $version, string $source): void { - if (!preg_match('/^(5\.[456]|7\.[01234]|8\.[012])(\..*)?$/', $version)) { - throw new UnexpectedValueException('Expecting a version number in the format x.y'); + if (!preg_match('/' . self::PHP_VERSION_REGEX . '/', $version)) { + throw new UnexpectedValueException('Expecting a version number in the format x.y or x.y.z'); + } + + if (!preg_match('/' . self::PHP_SUPPORTED_VERSIONS_REGEX . '/', $version)) { + throw new UnexpectedValueException( + 'Psalm supports PHP version ">=5.4". The specified version ' + . $version + . " is either not supported or doesn't exist.", + ); } [$php_major_version, $php_minor_version] = explode('.', $version); diff --git a/src/Psalm/Internal/CliUtils.php b/src/Psalm/Internal/CliUtils.php index 1e5a1abdd..86f6b3261 100644 --- a/src/Psalm/Internal/CliUtils.php +++ b/src/Psalm/Internal/CliUtils.php @@ -12,6 +12,7 @@ use Psalm\Exception\ConfigNotFoundException; use Psalm\Internal\Analyzer\ProjectAnalyzer; use Psalm\Report; use RuntimeException; +use UnexpectedValueException; use function array_filter; use function array_key_exists; @@ -485,7 +486,15 @@ final class CliUtils } if ($version !== null && $source !== null) { - $project_analyzer->setPhpVersion($version, $source); + try { + $project_analyzer->setPhpVersion($version, $source); + } catch (UnexpectedValueException $e) { + fwrite( + STDERR, + $e->getMessage() . PHP_EOL, + ); + exit(2); + } } } diff --git a/src/Psalm/Type/Reconciler.php b/src/Psalm/Type/Reconciler.php index 76bfb230d..4f93c7979 100644 --- a/src/Psalm/Type/Reconciler.php +++ b/src/Psalm/Type/Reconciler.php @@ -423,6 +423,10 @@ class Reconciler { foreach ($new_types as $nk => $type) { if (strpos($nk, '[') || strpos($nk, '->')) { + $type = array_values($type); + if (!isset($type[0][0])) { + continue; + } if ($type[0][0] instanceof IsEqualIsset || $type[0][0] instanceof IsIsset || $type[0][0] instanceof NonEmpty diff --git a/stubs/Php74.phpstub b/stubs/Php74.phpstub new file mode 100644 index 000000000..4ade3a6da --- /dev/null +++ b/stubs/Php74.phpstub @@ -0,0 +1,11 @@ + return + * + * @param null|string|array $allowed_tags + */ +function strip_tags(string $string, null|string|array $allowed_tags = null) : string {}