1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00
This commit is contained in:
Daniil Gentili 2023-10-22 20:11:28 +02:00
parent 71483b72aa
commit e8b7b30043
9 changed files with 58 additions and 100 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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',

View File

@ -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;

View File

@ -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,
],

View File

@ -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;
}