Skip to content

Commit

Permalink
Merge branch 'master' into missing-composer-lock-should-not-invalidat…
Browse files Browse the repository at this point in the history
…e-cache-created-with-missing-composer-lock
  • Loading branch information
orklah authored Jul 3, 2023
2 parents b877aa7 + 3e54feb commit a83c3fe
Show file tree
Hide file tree
Showing 49 changed files with 360 additions and 276 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-tokenizer": "*",
"composer-runtime-api": "^2",
"amphp/amp": "^2.4.2",
"amphp/byte-stream": "^1.5",
"composer-runtime-api": "^2",
"composer/semver": "^1.4 || ^2.0 || ^3.0",
"composer/xdebug-handler": "^2.0 || ^3.0",
"dnoegel/php-xdg-base-dir": "^0.1.1",
"felixfbecker/advanced-json-rpc": "^3.1",
"felixfbecker/language-server-protocol": "^1.5.2",
"fidry/cpu-core-counter": "^0.4.1 || ^0.5.1",
"netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0",
"nikic/php-parser": "^4.14",
"nikic/php-parser": "^4.16",
"sebastian/diff": "^4.0 || ^5.0",
"spatie/array-to-xml": "^2.17.0 || ^3.0",
"symfony/console": "^4.1.6 || ^5.0 || ^6.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/plugins/FunctionCasingChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public static function afterFunctionCallAnalysis(AfterFunctionCallAnalysisEvent

$function_name_parts = explode('\\', $function_storage->cased_name);

if (end($function_name_parts) !== end($expr->name->parts)) {
if (end($function_name_parts) !== $expr->name->getLast()) {
IssueBuffer::maybeAdd(
new IncorrectFunctionCasing(
'Function is incorrectly cased, expecting ' . $function_storage->cased_name,
Expand Down
2 changes: 1 addition & 1 deletion examples/plugins/StringChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static function afterExpressionAnalysis(AfterExpressionAnalysisEvent $eve
&& $expr->left->class instanceof PhpParser\Node\Name
&& $expr->left->name instanceof PhpParser\Node\Identifier
&& strtolower($expr->left->name->name) === 'class'
&& !in_array(strtolower($expr->left->class->parts[0]), ['self', 'static', 'parent'])
&& !in_array(strtolower($expr->left->class->getFirst()), ['self', 'static', 'parent'])
&& $expr->right instanceof PhpParser\Node\Scalar\String_
&& preg_match('/^::[A-Za-z0-9]+$/', $expr->right->value)
) {
Expand Down
1 change: 1 addition & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<MissingConstructor>
<errorLevel type="suppress">
<directory name="tests"/>
<file name="vendor/nikic/php-parser/lib/PhpParser/Node/Name.php" />
</errorLevel>
</MissingConstructor>

Expand Down
5 changes: 5 additions & 0 deletions src/Psalm/Config/Creator.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use function implode;
use function is_array;
use function is_dir;
use function is_string;
use function json_decode;
use function ksort;
use function max;
Expand Down Expand Up @@ -250,6 +251,10 @@ private static function getPsr4Or0Paths(string $current_dir, array $composer_jso
}

foreach ($paths as $path) {
if (!is_string($path)) {
continue;
}

if ($path === '') {
$nodes = [...$nodes, ...self::guessPhpFileDirs($current_dir)];

Expand Down
39 changes: 32 additions & 7 deletions src/Psalm/Config/FileFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use function in_array;
use function is_dir;
use function is_iterable;
use function is_string;
use function preg_match;
use function preg_replace;
use function preg_split;
Expand Down Expand Up @@ -57,12 +58,12 @@ class FileFilter
protected $fq_classlike_names = [];

/**
* @var array<string>
* @var array<non-empty-string>
*/
protected $fq_classlike_patterns = [];

/**
* @var array<string>
* @var array<non-empty-string>
*/
protected $method_ids = [];

Expand Down Expand Up @@ -314,22 +315,39 @@ public static function loadFromArray(
if (isset($config['referencedMethod']) && is_iterable($config['referencedMethod'])) {
/** @var array $referenced_method */
foreach ($config['referencedMethod'] as $referenced_method) {
$method_id = (string) ($referenced_method['name'] ?? '');

if (!preg_match('/^[^:]+::[^:]+$/', $method_id) && !static::isRegularExpression($method_id)) {
$method_id = $referenced_method['name'] ?? '';
if (!is_string($method_id)
|| (!preg_match('/^[^:]+::[^:]+$/', $method_id) && !static::isRegularExpression($method_id))) {
throw new ConfigException(
'Invalid referencedMethod ' . $method_id,
'Invalid referencedMethod ' . ((string) $method_id),
);
}

if ($method_id === '') {
continue;
}

$filter->method_ids[] = strtolower($method_id);
}
}

if (isset($config['referencedFunction']) && is_iterable($config['referencedFunction'])) {
/** @var array $referenced_function */
foreach ($config['referencedFunction'] as $referenced_function) {
$filter->method_ids[] = strtolower((string) ($referenced_function['name'] ?? ''));
$function_id = $referenced_function['name'] ?? '';
if (!is_string($function_id)
|| (!preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $function_id)
&& !static::isRegularExpression($function_id))) {
throw new ConfigException(
'Invalid referencedFunction ' . ((string) $function_id),
);
}

if ($function_id === '') {
continue;
}

$filter->method_ids[] = strtolower($function_id);
}
}

Expand Down Expand Up @@ -441,8 +459,15 @@ public static function loadFromXMLElement(
return self::loadFromArray($config, $base_dir, $inclusive);
}

/**
* @psalm-assert-if-true non-empty-string $string
*/
private static function isRegularExpression(string $string): bool
{
if ($string === '') {
return false;
}

set_error_handler(
static fn(): bool => true,
E_WARNING,
Expand Down
7 changes: 3 additions & 4 deletions src/Psalm/Internal/Analyzer/CanAlias.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Psalm\FileManipulation;
use Psalm\Internal\FileManipulation\FileManipulationBuffer;

use function implode;
use function strtolower;

/**
Expand Down Expand Up @@ -51,7 +50,7 @@ public function visitUse(PhpParser\Node\Stmt\Use_ $stmt): void
$codebase = $this->getCodebase();

foreach ($stmt->uses as $use) {
$use_path = implode('\\', $use->name->parts);
$use_path = $use->name->toString();
$use_path_lc = strtolower($use_path);
$use_alias = $use->alias->name ?? $use->name->getLast();
$use_alias_lc = strtolower($use_alias);
Expand Down Expand Up @@ -106,12 +105,12 @@ public function visitUse(PhpParser\Node\Stmt\Use_ $stmt): void

public function visitGroupUse(PhpParser\Node\Stmt\GroupUse $stmt): void
{
$use_prefix = implode('\\', $stmt->prefix->parts);
$use_prefix = $stmt->prefix->toString();

$codebase = $this->getCodebase();

foreach ($stmt->uses as $use) {
$use_path = $use_prefix . '\\' . implode('\\', $use->name->parts);
$use_path = $use_prefix . '\\' . $use->name->toString();
$use_alias = $use->alias->name ?? $use->name->getLast();

switch ($use->type !== PhpParser\Node\Stmt\Use_::TYPE_UNKNOWN ? $use->type : $stmt->type) {
Expand Down
4 changes: 2 additions & 2 deletions src/Psalm/Internal/Analyzer/ClassAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2021,7 +2021,7 @@ private function checkImplementedInterfaces(
. ($interface_name instanceof PhpParser\Node\Name\FullyQualified
? '\\'
: $this->getNamespace() . '-')
. implode('\\', $interface_name->parts),
. $interface_name->toString(),
);

$interface_location = new CodeLocation($this, $interface_name);
Expand Down Expand Up @@ -2437,7 +2437,7 @@ private function checkParentClass(
. ($extended_class instanceof PhpParser\Node\Name\FullyQualified
? '\\'
: $this->getNamespace() . '-')
. implode('\\', $extended_class->parts),
. $extended_class->toString(),
);
}

Expand Down
9 changes: 4 additions & 5 deletions src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
use function count;
use function explode;
use function gettype;
use function implode;
use function in_array;
use function preg_match;
use function preg_replace;
Expand Down Expand Up @@ -421,15 +420,15 @@ public static function getFQCLNFromNameObject(
}

if ($class_name instanceof PhpParser\Node\Name\FullyQualified) {
return implode('\\', $class_name->parts);
return $class_name->toString();
}

if (in_array($class_name->parts[0], ['self', 'static', 'parent'], true)) {
return $class_name->parts[0];
if (in_array($class_name->getFirst(), ['self', 'static', 'parent'], true)) {
return $class_name->getFirst();
}

return Type::getFQCLNFromString(
implode('\\', $class_name->parts),
$class_name->toString(),
$aliases,
);
}
Expand Down
3 changes: 1 addition & 2 deletions src/Psalm/Internal/Analyzer/FileAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
use function array_diff_key;
use function array_keys;
use function count;
use function implode;
use function strpos;
use function strtolower;

Expand Down Expand Up @@ -283,7 +282,7 @@ public function populateCheckers(array $stmts): array
} elseif ($stmt instanceof PhpParser\Node\Stmt\ClassLike) {
$this->populateClassLikeAnalyzers($stmt);
} elseif ($stmt instanceof PhpParser\Node\Stmt\Namespace_) {
$namespace_name = $stmt->name ? implode('\\', $stmt->name->parts) : '';
$namespace_name = $stmt->name ? $stmt->name->toString() : '';

$namespace_analyzer = new NamespaceAnalyzer($stmt, $this);
$namespace_analyzer->collectAnalyzableInformation();
Expand Down
3 changes: 1 addition & 2 deletions src/Psalm/Internal/Analyzer/NamespaceAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

use function assert;
use function count;
use function implode;
use function is_string;
use function preg_replace;
use function strpos;
Expand Down Expand Up @@ -49,7 +48,7 @@ public function __construct(Namespace_ $namespace, FileAnalyzer $source)
{
$this->source = $source;
$this->namespace = $namespace;
$this->namespace_name = $this->namespace->name ? implode('\\', $this->namespace->name->parts) : '';
$this->namespace_name = $this->namespace->name ? $this->namespace->name->toString() : '';
}

public function collectAnalyzableInformation(): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,13 @@ private static function getDefinitelyEvaluatedExpressionAfterIf(PhpParser\Node\E
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical
) {
if ($stmt->left instanceof PhpParser\Node\Expr\ConstFetch
&& $stmt->left->name->parts === ['true']
&& $stmt->left->name->getParts() === ['true']
) {
return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->right);
}

if ($stmt->right instanceof PhpParser\Node\Expr\ConstFetch
&& $stmt->right->name->parts === ['true']
&& $stmt->right->name->getParts() === ['true']
) {
return self::getDefinitelyEvaluatedExpressionAfterIf($stmt->left);
}
Expand Down Expand Up @@ -282,13 +282,13 @@ private static function getDefinitelyEvaluatedExpressionInsideIf(PhpParser\Node\
|| $stmt instanceof PhpParser\Node\Expr\BinaryOp\Identical
) {
if ($stmt->left instanceof PhpParser\Node\Expr\ConstFetch
&& $stmt->left->name->parts === ['true']
&& $stmt->left->name->getParts() === ['true']
) {
return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->right);
}

if ($stmt->right instanceof PhpParser\Node\Expr\ConstFetch
&& $stmt->right->name->parts === ['true']
&& $stmt->right->name->getParts() === ['true']
) {
return self::getDefinitelyEvaluatedExpressionInsideIf($stmt->left);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public static function analyze(
}

if ($switch_condition instanceof PhpParser\Node\Expr\ConstFetch
&& $switch_condition->name->parts === ['true']
&& $switch_condition->name->getParts() === ['true']
) {
$case_equality_expr = $case->cond;
} elseif (($switch_condition_type = $statements_analyzer->node_data->getType($switch_condition))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public static function analyze(
PhpParser\Node\Stmt\While_ $stmt,
Context $context
): ?bool {
$while_true = ($stmt->cond instanceof PhpParser\Node\Expr\ConstFetch && $stmt->cond->name->parts === ['true'])
$while_true = ($stmt->cond instanceof PhpParser\Node\Expr\ConstFetch
&& $stmt->cond->name->getParts() === ['true'])
|| (($t = $statements_analyzer->node_data->getType($stmt->cond))
&& $t->isAlwaysTruthy());

Expand Down
Loading

0 comments on commit a83c3fe

Please sign in to comment.