mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Fixes
This commit is contained in:
parent
71483b72aa
commit
e8b7b30043
@ -44,6 +44,14 @@
|
||||
|
||||
- [BC] `Psalm\CodeLocation\Raw`, `Psalm\CodeLocation\ParseErrorLocation`, `Psalm\CodeLocation\DocblockTypeLocation`, `Psalm\Report\CountReport`, `Psalm\Type\Atomic\TNonEmptyArray` are now all final.
|
||||
|
||||
- [BC] `Psalm\Config` is now final.
|
||||
|
||||
- [BC] The return type of `Psalm\Plugin\ArgTypeInferer::infer` changed from `Union|false` to `Union|null`
|
||||
|
||||
- [BC] The `extra_types` property and `setIntersectionTypes` method of `Psalm\Type\Atomic\TTypeAlias` were removed.
|
||||
|
||||
- [BC] Methods `convertSeverity` and `calculateFingerprint` of `Psalm\Report\CodeClimateReport` were removed.
|
||||
|
||||
# Upgrading from Psalm 4 to Psalm 5
|
||||
## Changed
|
||||
|
||||
|
@ -69,7 +69,6 @@ use function file_get_contents;
|
||||
use function flock;
|
||||
use function fopen;
|
||||
use function function_exists;
|
||||
use function get_class;
|
||||
use function get_defined_constants;
|
||||
use function get_defined_functions;
|
||||
use function getcwd;
|
||||
@ -98,7 +97,9 @@ use function rtrim;
|
||||
use function scandir;
|
||||
use function sha1;
|
||||
use function simplexml_import_dom;
|
||||
use function str_contains;
|
||||
use function str_replace;
|
||||
use function str_starts_with;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function strrpos;
|
||||
@ -127,13 +128,13 @@ use const SCANDIR_SORT_NONE;
|
||||
* @psalm-suppress PropertyNotSetInConstructor
|
||||
* @psalm-consistent-constructor
|
||||
*/
|
||||
class Config
|
||||
final class Config
|
||||
{
|
||||
private const DEFAULT_FILE_NAME = 'psalm.xml';
|
||||
public const CONFIG_NAMESPACE = 'https://getpsalm.org/schema/config';
|
||||
public const REPORT_INFO = 'info';
|
||||
public const REPORT_ERROR = 'error';
|
||||
public const REPORT_SUPPRESS = 'suppress';
|
||||
final public const CONFIG_NAMESPACE = 'https://getpsalm.org/schema/config';
|
||||
final public const REPORT_INFO = 'info';
|
||||
final public const REPORT_ERROR = 'error';
|
||||
final public const REPORT_SUPPRESS = 'suppress';
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
@ -172,7 +173,7 @@ class Config
|
||||
*
|
||||
* @var array<int, lowercase-string>
|
||||
*/
|
||||
protected array $universal_object_crates;
|
||||
private array $universal_object_crates;
|
||||
|
||||
/**
|
||||
* @var static|null
|
||||
@ -222,7 +223,7 @@ class Config
|
||||
|
||||
protected ?ProjectFileFilter $project_files = null;
|
||||
|
||||
protected ?ProjectFileFilter $extra_files = null;
|
||||
private ?ProjectFileFilter $extra_files = null;
|
||||
|
||||
/**
|
||||
* The base directory of this config file
|
||||
@ -426,7 +427,7 @@ class Config
|
||||
|
||||
private ?IncludeCollector $include_collector = null;
|
||||
|
||||
protected ?TaintAnalysisFileFilter $taint_analysis_ignored_files = null;
|
||||
private ?TaintAnalysisFileFilter $taint_analysis_ignored_files = null;
|
||||
|
||||
/**
|
||||
* @var bool whether to emit a backtrace of emitted issues to stderr
|
||||
@ -874,7 +875,6 @@ class Config
|
||||
/**
|
||||
* @param non-empty-string $file_contents
|
||||
* @psalm-suppress MixedAssignment
|
||||
* @psalm-suppress MixedArgument
|
||||
* @psalm-suppress MixedPropertyFetch
|
||||
* @throws ConfigException
|
||||
*/
|
||||
@ -963,15 +963,15 @@ class Config
|
||||
if (file_exists($composer_json_path)) {
|
||||
$composer_json_contents = file_get_contents($composer_json_path);
|
||||
assert($composer_json_contents !== false);
|
||||
$composer_json = json_decode($composer_json_contents, true);
|
||||
$composer_json = json_decode($composer_json_contents, true, 512, JSON_THROW_ON_ERROR);
|
||||
if (!is_array($composer_json)) {
|
||||
throw new UnexpectedValueException('Invalid composer.json at ' . $composer_json_path);
|
||||
}
|
||||
}
|
||||
$required_extensions = [];
|
||||
foreach (($composer_json["require"] ?? []) as $required => $_) {
|
||||
if (strpos($required, "ext-") === 0) {
|
||||
$required_extensions[strtolower(substr($required, 4))] = true;
|
||||
if (str_starts_with((string) $required, "ext-")) {
|
||||
$required_extensions[strtolower(substr((string) $required, 4))] = true;
|
||||
}
|
||||
}
|
||||
foreach ($required_extensions as $required_ext => $_) {
|
||||
@ -1649,7 +1649,7 @@ class Config
|
||||
try {
|
||||
$file_storage = $codebase->file_storage_provider->get($file_path);
|
||||
$dependent_files += $file_storage->required_by_file_paths;
|
||||
} catch (InvalidArgumentException $e) {
|
||||
} catch (InvalidArgumentException) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@ -1700,7 +1700,7 @@ class Config
|
||||
|
||||
public function getReportingLevelForIssue(CodeIssue $e): string
|
||||
{
|
||||
$fqcn_parts = explode('\\', get_class($e));
|
||||
$fqcn_parts = explode('\\', $e::class);
|
||||
$issue_type = array_pop($fqcn_parts);
|
||||
|
||||
$reporting_level = null;
|
||||
@ -1765,17 +1765,17 @@ class Config
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strpos($issue_type, 'Possibly') === 0) {
|
||||
if (str_starts_with($issue_type, 'Possibly')) {
|
||||
$stripped_issue_type = (string) preg_replace('/^Possibly(False|Null)?/', '', $issue_type, 1);
|
||||
|
||||
if (strpos($stripped_issue_type, 'Invalid') === false && strpos($stripped_issue_type, 'Un') !== 0) {
|
||||
if (!str_contains($stripped_issue_type, 'Invalid') && !str_starts_with($stripped_issue_type, 'Un')) {
|
||||
$stripped_issue_type = 'Invalid' . $stripped_issue_type;
|
||||
}
|
||||
|
||||
return $stripped_issue_type;
|
||||
}
|
||||
|
||||
if (strpos($issue_type, 'Tainted') === 0) {
|
||||
if (str_starts_with($issue_type, 'Tainted')) {
|
||||
return 'TaintedInput';
|
||||
}
|
||||
|
||||
@ -2298,7 +2298,7 @@ class Config
|
||||
$codebase->classlikes->forgetMissingClassLikes();
|
||||
|
||||
$this->include_collector->runAndCollect(
|
||||
[$this, 'requireAutoloader'],
|
||||
$this->requireAutoloader(...),
|
||||
);
|
||||
}
|
||||
|
||||
@ -2324,7 +2324,8 @@ class Config
|
||||
}
|
||||
}
|
||||
|
||||
public function getComposerFilePathForClassLike(string $fq_classlike_name): string|false
|
||||
/** @return string|false */
|
||||
public function getComposerFilePathForClassLike(string $fq_classlike_name): string|bool
|
||||
{
|
||||
if (!$this->composer_class_loader) {
|
||||
return false;
|
||||
@ -2502,7 +2503,7 @@ class Config
|
||||
$composer_json_contents = file_get_contents($composer_json_path);
|
||||
assert($composer_json_contents !== false);
|
||||
$composer_json = json_decode($composer_json_contents, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
} catch (JsonException) {
|
||||
$composer_json = null;
|
||||
}
|
||||
|
||||
|
@ -13,19 +13,16 @@ use Psalm\Type\Union;
|
||||
|
||||
final class ArgTypeInferer
|
||||
{
|
||||
private Context $context;
|
||||
private StatementsAnalyzer $statements_analyzer;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(Context $context, StatementsAnalyzer $statements_analyzer)
|
||||
{
|
||||
$this->context = $context;
|
||||
$this->statements_analyzer = $statements_analyzer;
|
||||
public function __construct(
|
||||
private readonly Context $context,
|
||||
private readonly StatementsAnalyzer $statements_analyzer,
|
||||
) {
|
||||
}
|
||||
|
||||
public function infer(PhpParser\Node\Arg $arg): false|Union
|
||||
public function infer(PhpParser\Node\Arg $arg): null|Union
|
||||
{
|
||||
$already_inferred_type = $this->statements_analyzer->node_data->getType($arg->value);
|
||||
|
||||
@ -34,7 +31,7 @@ final class ArgTypeInferer
|
||||
}
|
||||
|
||||
if (ExpressionAnalyzer::analyze($this->statements_analyzer, $arg->value, $this->context) === false) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->statements_analyzer->node_data->getType($arg->value) ?? Type::getMixed();
|
||||
|
@ -28,7 +28,7 @@ final class CodeClimateReport extends Report
|
||||
$options = $this->pretty ? Json::PRETTY : Json::DEFAULT;
|
||||
|
||||
$issues_data = array_map(
|
||||
[$this, 'mapToNewStructure'],
|
||||
$this->mapToNewStructure(...),
|
||||
$this->issues_data,
|
||||
);
|
||||
|
||||
@ -39,7 +39,7 @@ final class CodeClimateReport extends Report
|
||||
* convert our own severity to CodeClimate format
|
||||
* Values can be : info, minor, major, critical, or blocker
|
||||
*/
|
||||
protected function convertSeverity(string $input): string
|
||||
private function convertSeverity(string $input): string
|
||||
{
|
||||
if (Config::REPORT_INFO === $input) {
|
||||
return 'info';
|
||||
@ -58,7 +58,7 @@ final class CodeClimateReport extends Report
|
||||
/**
|
||||
* calculate a unique fingerprint for a given issue
|
||||
*/
|
||||
protected function calculateFingerprint(IssueData $issue): string
|
||||
private function calculateFingerprint(IssueData $issue): string
|
||||
{
|
||||
return md5($issue->type.$issue->message.$issue->file_name.$issue->from.$issue->to);
|
||||
}
|
||||
|
@ -6,55 +6,17 @@ namespace Psalm\Type\Atomic;
|
||||
|
||||
use Psalm\Type\Atomic;
|
||||
|
||||
use function array_map;
|
||||
use function implode;
|
||||
|
||||
/**
|
||||
* @psalm-immutable
|
||||
*/
|
||||
final class TTypeAlias extends Atomic
|
||||
{
|
||||
/**
|
||||
* @var array<string, TTypeAlias>|null
|
||||
* @deprecated type aliases are resolved within {@see TypeParser::resolveTypeAliases()} and therefore the
|
||||
* referencing type(s) are part of other intersection types. The intersection types are not set anymore
|
||||
* and with v6 this property along with its related methods will get removed.
|
||||
*/
|
||||
public ?array $extra_types = null;
|
||||
|
||||
public string $declaring_fq_classlike_name;
|
||||
|
||||
public string $alias_name;
|
||||
|
||||
/**
|
||||
* @param array<string, TTypeAlias>|null $extra_types
|
||||
*/
|
||||
public function __construct(string $declaring_fq_classlike_name, string $alias_name, ?array $extra_types = null)
|
||||
{
|
||||
$this->declaring_fq_classlike_name = $declaring_fq_classlike_name;
|
||||
$this->alias_name = $alias_name;
|
||||
/** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */
|
||||
$this->extra_types = $extra_types;
|
||||
public function __construct(
|
||||
public string $declaring_fq_classlike_name,
|
||||
public string $alias_name,
|
||||
) {
|
||||
parent::__construct(true);
|
||||
}
|
||||
/**
|
||||
* @param array<string, TTypeAlias>|null $extra_types
|
||||
* @deprecated type aliases are resolved within {@see TypeParser::resolveTypeAliases()} and therefore the
|
||||
* referencing type(s) are part of other intersection types. This method will get removed with v6.
|
||||
* @psalm-suppress PossiblyUnusedMethod For backwards compatibility, we have to keep this here.
|
||||
*/
|
||||
public function setIntersectionTypes(?array $extra_types): self
|
||||
{
|
||||
/** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */
|
||||
if ($extra_types === $this->extra_types) {
|
||||
return $this;
|
||||
}
|
||||
return new self(
|
||||
$this->declaring_fq_classlike_name,
|
||||
$this->alias_name,
|
||||
$extra_types,
|
||||
);
|
||||
}
|
||||
|
||||
public function getKey(bool $include_extra = true): string
|
||||
{
|
||||
@ -63,17 +25,6 @@ final class TTypeAlias extends Atomic
|
||||
|
||||
public function getId(bool $exact = true, bool $nested = false): string
|
||||
{
|
||||
/** @psalm-suppress DeprecatedProperty For backwards compatibility, we have to keep this here. */
|
||||
if ($this->extra_types) {
|
||||
return $this->getKey() . '&' . implode(
|
||||
'&',
|
||||
array_map(
|
||||
static fn(Atomic $type): string => $type->getId($exact, true),
|
||||
$this->extra_types,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
|
@ -632,7 +632,7 @@ class EnumTest extends TestCase
|
||||
$foo = FooEnum::Foo->value;
|
||||
noop($foo);
|
||||
noop(FooEnum::Foo->value);
|
||||
PHP,
|
||||
PHP,
|
||||
'assertions' => [],
|
||||
'ignored_issues' => [],
|
||||
'php_version' => '8.1',
|
||||
|
@ -25,9 +25,9 @@ class PsalmPluginTest extends TestCase
|
||||
{
|
||||
use MockeryPHPUnitIntegration;
|
||||
|
||||
private PluginList&MockInterface $plugin_list;
|
||||
private MockInterface $plugin_list;
|
||||
|
||||
private PluginListFactory&MockInterface $plugin_list_factory;
|
||||
private MockInterface $plugin_list_factory;
|
||||
|
||||
private Application $app;
|
||||
|
||||
|
@ -712,6 +712,7 @@ class ReportOutputTest extends TestCase
|
||||
|
||||
$issue_data = [
|
||||
[
|
||||
'link' => 'https://psalm.dev/024',
|
||||
'severity' => 'error',
|
||||
'line_from' => 3,
|
||||
'line_to' => 3,
|
||||
@ -727,13 +728,13 @@ class ReportOutputTest extends TestCase
|
||||
'snippet_to' => 83,
|
||||
'column_from' => 10,
|
||||
'column_to' => 26,
|
||||
'error_level' => -1,
|
||||
'shortcode' => 24,
|
||||
'link' => 'https://psalm.dev/024',
|
||||
'error_level' => -1,
|
||||
'taint_trace' => null,
|
||||
'other_references' => null,
|
||||
],
|
||||
[
|
||||
'link' => 'https://psalm.dev/138',
|
||||
'severity' => 'error',
|
||||
'line_from' => 3,
|
||||
'line_to' => 3,
|
||||
@ -749,13 +750,13 @@ class ReportOutputTest extends TestCase
|
||||
'snippet_to' => 83,
|
||||
'column_from' => 10,
|
||||
'column_to' => 26,
|
||||
'error_level' => 1,
|
||||
'shortcode' => 138,
|
||||
'link' => 'https://psalm.dev/138',
|
||||
'error_level' => 1,
|
||||
'taint_trace' => null,
|
||||
'other_references' => null,
|
||||
],
|
||||
[
|
||||
'link' => 'https://psalm.dev/047',
|
||||
'severity' => 'error',
|
||||
'line_from' => 2,
|
||||
'line_to' => 2,
|
||||
@ -771,13 +772,13 @@ class ReportOutputTest extends TestCase
|
||||
'snippet_to' => 56,
|
||||
'column_from' => 42,
|
||||
'column_to' => 49,
|
||||
'error_level' => 1,
|
||||
'shortcode' => 47,
|
||||
'link' => 'https://psalm.dev/047',
|
||||
'error_level' => 1,
|
||||
'taint_trace' => null,
|
||||
'other_references' => null,
|
||||
],
|
||||
[
|
||||
'link' => 'https://psalm.dev/020',
|
||||
'severity' => 'error',
|
||||
'line_from' => 8,
|
||||
'line_to' => 8,
|
||||
@ -793,13 +794,13 @@ class ReportOutputTest extends TestCase
|
||||
'snippet_to' => 172,
|
||||
'column_from' => 6,
|
||||
'column_to' => 15,
|
||||
'error_level' => -1,
|
||||
'shortcode' => 20,
|
||||
'link' => 'https://psalm.dev/020',
|
||||
'error_level' => -1,
|
||||
'taint_trace' => null,
|
||||
'other_references' => null,
|
||||
],
|
||||
[
|
||||
'link' => 'https://psalm.dev/126',
|
||||
'severity' => 'info',
|
||||
'line_from' => 17,
|
||||
'line_to' => 17,
|
||||
@ -815,9 +816,8 @@ class ReportOutputTest extends TestCase
|
||||
'snippet_to' => 277,
|
||||
'column_from' => 6,
|
||||
'column_to' => 8,
|
||||
'error_level' => 3,
|
||||
'shortcode' => 126,
|
||||
'link' => 'https://psalm.dev/126',
|
||||
'error_level' => 3,
|
||||
'taint_trace' => null,
|
||||
'other_references' => null,
|
||||
],
|
||||
|
@ -61,7 +61,8 @@ class TestConfig extends Config
|
||||
</projectFiles>';
|
||||
}
|
||||
|
||||
public function getComposerFilePathForClassLike(string $fq_classlike_name): string|false
|
||||
/** @return false */
|
||||
public function getComposerFilePathForClassLike(string $fq_classlike_name): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user