Skip to content

Commit

Permalink
Merge pull request #10310 from nicelocal/v6_fixes
Browse files Browse the repository at this point in the history
V6 fixes
  • Loading branch information
orklah authored Oct 22, 2023
2 parents 75fcfe3 + e72fb5a commit 147505c
Show file tree
Hide file tree
Showing 89 changed files with 878 additions and 320 deletions.
8 changes: 8 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"amphp/phpunit-util": "^3",
"bamarni/composer-bin-plugin": "^1.4",
"brianium/paratest": "^6.9",
"dg/bypass-finals": "^1.5",
"mockery/mockery": "^1.5",
"nunomaduro/mock-final-classes": "^1.1",
"php-parallel-lint/php-parallel-lint": "^1.2",
Expand Down
13 changes: 10 additions & 3 deletions dictionaries/CallMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -12886,10 +12886,16 @@
'str_contains' => ['bool', 'haystack'=>'string', 'needle'=>'string'],
'str_ends_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'],
'str_getcsv' => ['non-empty-list<?string>', 'string'=>'string', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'],
'str_ireplace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_ireplace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_ireplace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_pad' => ['string', 'string'=>'string', 'length'=>'int', 'pad_string='=>'string', 'pad_type='=>'int'],
'str_repeat' => ['string', 'string'=>'string', 'times'=>'int'],
'str_replace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_replace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_replace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_rot13' => ['string', 'string'=>'string'],
'str_shuffle' => ['string', 'string'=>'string'],
'str_split' => ['list<non-empty-string>', 'string'=>'string', 'length='=>'positive-int'],
Expand Down Expand Up @@ -13015,7 +13021,8 @@
'substr' => ['string', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'],
'substr_compare' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'?int', 'case_insensitive='=>'bool'],
'substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'?int'],
'substr_replace' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'substr_replace' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'substr_replace\'1' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'suhosin_encrypt_cookie' => ['string|false', 'name'=>'string', 'value'=>'string'],
'suhosin_get_raw_cookies' => ['array'],
'SVM::__construct' => ['void'],
Expand Down
8 changes: 6 additions & 2 deletions dictionaries/CallMap_80_delta.php
Original file line number Diff line number Diff line change
Expand Up @@ -2589,8 +2589,12 @@
'new' => ['string', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'],
],
'substr_replace' => [
'old' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'new' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'old' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'new' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
],
'substr_replace\'1' => [
'old' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'new' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
],
'tidy_parse_file' => [
'old' => ['tidy', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'],
Expand Down
13 changes: 10 additions & 3 deletions dictionaries/CallMap_historical.php
Original file line number Diff line number Diff line change
Expand Up @@ -14303,10 +14303,16 @@
'stomp_unsubscribe' => ['bool', 'link'=>'resource', 'destination'=>'string', 'headers='=>'?array'],
'stomp_version' => ['string'],
'str_getcsv' => ['non-empty-list<?string>', 'string'=>'string', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'],
'str_ireplace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_ireplace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_ireplace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_pad' => ['string', 'string'=>'string', 'length'=>'int', 'pad_string='=>'string', 'pad_type='=>'int'],
'str_repeat' => ['string', 'string'=>'string', 'times'=>'int'],
'str_replace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_replace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_replace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_rot13' => ['string', 'string'=>'string'],
'str_shuffle' => ['string', 'string'=>'string'],
'str_split' => ['non-empty-list<string>', 'string'=>'string', 'length='=>'positive-int'],
Expand Down Expand Up @@ -14430,7 +14436,8 @@
'substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'int'],
'substr_compare' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'int', 'case_insensitive='=>'bool'],
'substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'int'],
'substr_replace' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'substr_replace' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'substr_replace\'1' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'suhosin_encrypt_cookie' => ['string|false', 'name'=>'string', 'value'=>'string'],
'suhosin_get_raw_cookies' => ['array'],
'svm::crossvalidate' => ['float', 'problem'=>'array', 'number_of_folds'=>'int'],
Expand Down
3 changes: 2 additions & 1 deletion dictionaries/ImpureFunctionsList.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
'socket_set_block' => true,
'socket_set_nonblock' => true,
'socket_listen' => true,
'stream_socket_shutdown' => true,
'socket_shutdown' => true,
// meta calls
'call_user_func' => true,
'call_user_func_array' => true,
Expand All @@ -93,7 +95,6 @@
'mcrypt_generic_deinit' => true,
'mcrypt_module_close' => true,
// internal optimisation
'opcache_compile_file' => true,
'clearstatcache' => true,
// process-related
'pcntl_signal' => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
$removed_foreign_functions
);

uksort($new_local, fn($a, $b) => strtolower($a) <=> strtolower($b));
uksort($new_local, static fn($a, $b) => strtolower($a) <=> strtolower($b));

foreach ($new_local as $name => $data) {
if (!is_array($data)) {
Expand Down
1 change: 1 addition & 0 deletions docs/security_analysis/custom_taint_sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class BadSqlTainter implements AfterExpressionAnalysisInterface
);
}
}
return null;
}
}
```
2 changes: 1 addition & 1 deletion examples/plugins/ClassUnqualifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static function afterClassLikeExistenceCheck(
$new_candidate_type = implode(
'',
array_map(
fn($f) => $f[0],
static fn($f) => $f[0],
$type_tokens,
),
);
Expand Down
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
bootstrap="tests/autoload.php"
backupGlobals="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
Expand Down
15 changes: 14 additions & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="dev-master@973a3fa554b4a2016e2a551dce2206fb47084050">
<files psalm-version="dev-master@292ed063233e29d59d0bde61bb6daedee94d55bb">
<file src="examples/TemplateChecker.php">
<PossiblyUndefinedIntArrayOffset>
<code><![CDATA[$comment_block->tags['variablesfrom'][0]]]></code>
Expand All @@ -16,6 +16,9 @@
<PossiblyNullArgument>
<code>$deprecated_element_xml</code>
</PossiblyNullArgument>
<PropertyTypeCoercion>
<code>$this</code>
</PropertyTypeCoercion>
</file>
<file src="src/Psalm/Config/FileFilter.php">
<PossiblyUndefinedIntArrayOffset>
Expand Down Expand Up @@ -622,6 +625,16 @@
<code>hasLowercaseString</code>
</PossiblyUnusedMethod>
</file>
<file src="tests/TestConfig.php">
<InvalidExtendClass>
<code>Config</code>
</InvalidExtendClass>
<MethodSignatureMismatch>
<code>public function __construct()</code>
<code>public function getComposerFilePathForClassLike(string $fq_classlike_name): bool</code>
<code>public function getProjectDirectories(): array</code>
</MethodSignatureMismatch>
</file>
<file src="vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php">
<PossiblyUndefinedStringArrayOffset>
<code><![CDATA[$subNodes['expr']]]></code>
Expand Down
3 changes: 1 addition & 2 deletions src/Psalm/Codebase.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
use UnexpectedValueException;

use function array_combine;
use function array_merge;
use function array_pop;
use function array_reverse;
use function array_values;
Expand Down Expand Up @@ -1605,7 +1604,7 @@ public function getCompletionItemsForClassishThing(
);
}

$completion_items = array_merge($completion_items, array_values($pseudo_property_types));
$completion_items = [...$completion_items, ...array_values($pseudo_property_types)];

foreach ($class_storage->declaring_property_ids as $property_name => $declaring_class) {
$property_storage = $this->properties->getStorage(
Expand Down
43 changes: 22 additions & 21 deletions src/Psalm/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
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;
Expand Down Expand Up @@ -98,7 +97,9 @@
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;
Expand Down Expand Up @@ -127,13 +128,13 @@
* @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>
Expand Down Expand Up @@ -172,7 +173,7 @@ class Config
*
* @var array<int, lowercase-string>
*/
protected array $universal_object_crates;
private array $universal_object_crates;

/**
* @var static|null
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -874,7 +875,6 @@ private static function processConfigDeprecations(
/**
* @param non-empty-string $file_contents
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArgument
* @psalm-suppress MixedPropertyFetch
* @throws ConfigException
*/
Expand Down Expand Up @@ -963,15 +963,15 @@ private static function fromXmlAndPaths(
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 => $_) {
Expand Down Expand Up @@ -1649,7 +1649,7 @@ public function reportIssueInFile(string $issue_type, string $file_path): bool
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
}
}
Expand Down Expand Up @@ -1700,7 +1700,7 @@ public function trackTaintsInPath(string $file_path): bool

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;
Expand Down Expand Up @@ -1765,17 +1765,17 @@ public static function getParentIssueType(string $issue_type): ?string
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';
}

Expand Down Expand Up @@ -2298,7 +2298,7 @@ public function visitComposerAutoloadFiles(ProjectAnalyzer $project_analyzer, ?P
$codebase->classlikes->forgetMissingClassLikes();

$this->include_collector->runAndCollect(
[$this, 'requireAutoloader'],
$this->requireAutoloader(...),
);
}

Expand All @@ -2324,7 +2324,8 @@ public function visitComposerAutoloadFiles(ProjectAnalyzer $project_analyzer, ?P
}
}

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;
Expand Down Expand Up @@ -2502,7 +2503,7 @@ public function getPHPVersionFromComposerJson(): ?string
$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;
}

Expand Down
6 changes: 5 additions & 1 deletion src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ public static function checkFullyQualifiedClassLikeName(
?string $calling_method_id,
array $suppressed_issues,
?ClassLikeNameOptions $options = null,
bool $check_classes = true,
): ?bool {
if ($options === null) {
$options = new ClassLikeNameOptions();
Expand Down Expand Up @@ -278,6 +279,9 @@ public static function checkFullyQualifiedClassLikeName(
&& !($interface_exists && $options->allow_interface)
&& !($enum_exists && $options->allow_enum)
) {
if (!$check_classes) {
return null;
}
if (!$options->allow_trait || !$codebase->classlikes->traitExists($fq_class_name, $code_location)) {
if ($options->from_docblock) {
if (IssueBuffer::accepts(
Expand Down Expand Up @@ -703,7 +707,7 @@ protected function checkTemplateParams(
&& $storage->template_types
&& $storage->template_covariants
&& ($local_offset
= array_search($t->param_name, array_keys($storage->template_types)))
= array_search($t->param_name, array_keys($storage->template_types), true))
!== false
&& !empty($storage->template_covariants[$local_offset])
) {
Expand Down
Loading

0 comments on commit 147505c

Please sign in to comment.