mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 12:24:49 +01:00
Fix issue with $this instanceof checks in traits
This commit is contained in:
parent
967b51d5fc
commit
bc35f88859
@ -118,7 +118,7 @@ class IfChecker
|
||||
$reconcilable_if_types,
|
||||
$if_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->cond, $context->include_location),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -156,7 +156,7 @@ class IfChecker
|
||||
$if_scope->negated_types,
|
||||
$temp_else_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->cond, $context->include_location),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -349,7 +349,7 @@ class IfChecker
|
||||
$if_scope->negated_types,
|
||||
$outer_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation(
|
||||
$statements_checker->getSource(),
|
||||
$stmt->cond,
|
||||
@ -441,7 +441,7 @@ class IfChecker
|
||||
$if_scope->negated_types,
|
||||
$elseif_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation(
|
||||
$statements_checker->getSource(),
|
||||
$elseif->cond,
|
||||
@ -516,7 +516,7 @@ class IfChecker
|
||||
$reconcilable_elseif_types,
|
||||
$elseif_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $elseif->cond, $outer_context->include_location),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -634,7 +634,7 @@ class IfChecker
|
||||
$negated_elseif_types,
|
||||
$pre_conditional_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $elseif, $outer_context->include_location),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -757,7 +757,7 @@ class IfChecker
|
||||
$else_types,
|
||||
$else_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $else, $outer_context->include_location),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
|
@ -58,7 +58,7 @@ class WhileChecker
|
||||
$reconcilable_while_types,
|
||||
$while_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->cond),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -101,7 +101,7 @@ class WhileChecker
|
||||
$negated_while_types,
|
||||
$context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->cond),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
|
@ -125,7 +125,7 @@ class AssignmentChecker
|
||||
$array_var_id,
|
||||
$context->vars_in_scope[$array_var_id],
|
||||
$assign_value_type,
|
||||
$statements_checker->getFileChecker()
|
||||
$statements_checker
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ class CallChecker
|
||||
$assert_type_assertions,
|
||||
$context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
|
@ -634,7 +634,7 @@ class ExpressionChecker
|
||||
$var_id,
|
||||
$existing_type,
|
||||
$by_ref_type,
|
||||
$statements_checker->getFileChecker()
|
||||
$statements_checker
|
||||
);
|
||||
|
||||
if ((string)$existing_type !== 'array<empty, empty>') {
|
||||
@ -790,7 +790,7 @@ class ExpressionChecker
|
||||
$left_type_assertions,
|
||||
$context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -862,7 +862,7 @@ class ExpressionChecker
|
||||
$negated_type_assertions,
|
||||
$context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -896,7 +896,7 @@ class ExpressionChecker
|
||||
'!empty',
|
||||
$context->vars_in_scope[$var_id],
|
||||
'',
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->left),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -953,7 +953,7 @@ class ExpressionChecker
|
||||
$reconcilable_if_types,
|
||||
$t_if_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->left),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -990,7 +990,7 @@ class ExpressionChecker
|
||||
$negated_if_types,
|
||||
$t_else_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->right),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -1770,7 +1770,7 @@ class ExpressionChecker
|
||||
$reconcilable_if_types,
|
||||
$t_if_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->cond),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -1806,7 +1806,7 @@ class ExpressionChecker
|
||||
$negated_if_types,
|
||||
$t_else_context->vars_in_scope,
|
||||
$changed_vars,
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt->else),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
@ -1847,7 +1847,7 @@ class ExpressionChecker
|
||||
'!empty',
|
||||
$stmt->cond->inferredType,
|
||||
'',
|
||||
$statements_checker->getFileChecker(),
|
||||
$statements_checker,
|
||||
new CodeLocation($statements_checker->getSource(), $stmt),
|
||||
$statements_checker->getSuppressedIssues()
|
||||
);
|
||||
|
@ -34,7 +34,7 @@ class TypeChecker
|
||||
* @param array<string, string> $new_types
|
||||
* @param array<string, Type\Union> $existing_types
|
||||
* @param array<string> $changed_types
|
||||
* @param FileChecker $file_checker
|
||||
* @param StatementsChecker $statements_checker
|
||||
* @param CodeLocation $code_location
|
||||
* @param array<string> $suppressed_issues
|
||||
*
|
||||
@ -44,7 +44,7 @@ class TypeChecker
|
||||
array $new_types,
|
||||
array $existing_types,
|
||||
array &$changed_types,
|
||||
FileChecker $file_checker,
|
||||
StatementsChecker $statements_checker,
|
||||
CodeLocation $code_location,
|
||||
array $suppressed_issues = []
|
||||
) {
|
||||
@ -75,7 +75,7 @@ class TypeChecker
|
||||
|
||||
$result_type = isset($existing_types[$key])
|
||||
? clone $existing_types[$key]
|
||||
: self::getValueForKey($key, $existing_types, $file_checker);
|
||||
: self::getValueForKey($key, $existing_types, $statements_checker->getFileChecker());
|
||||
|
||||
if ($result_type && empty($result_type->types)) {
|
||||
throw new \InvalidArgumentException('Union::$types cannot be empty after get value for ' . $key);
|
||||
@ -90,7 +90,7 @@ class TypeChecker
|
||||
(string) $new_type_part,
|
||||
$result_type,
|
||||
$key,
|
||||
$file_checker,
|
||||
$statements_checker,
|
||||
$code_location,
|
||||
$suppressed_issues,
|
||||
$failed_reconciliation
|
||||
@ -136,7 +136,7 @@ class TypeChecker
|
||||
* @param string $new_var_type
|
||||
* @param Type\Union|null $existing_var_type
|
||||
* @param string|null $key
|
||||
* @param FileChecker $file_checker
|
||||
* @param StatementsChecker $statements_checker
|
||||
* @param CodeLocation $code_location
|
||||
* @param array $suppressed_issues
|
||||
* @param bool $failed_reconciliation if the types cannot be reconciled, we need to know
|
||||
@ -147,11 +147,13 @@ class TypeChecker
|
||||
$new_var_type,
|
||||
$existing_var_type,
|
||||
$key,
|
||||
FileChecker $file_checker,
|
||||
StatementsChecker $statements_checker,
|
||||
CodeLocation $code_location = null,
|
||||
array $suppressed_issues = [],
|
||||
&$failed_reconciliation = false
|
||||
) {
|
||||
$file_checker = $statements_checker->getFileChecker();
|
||||
|
||||
if ($existing_var_type === null) {
|
||||
if ($new_var_type === '^isset') {
|
||||
return null;
|
||||
@ -249,7 +251,9 @@ class TypeChecker
|
||||
$existing_var_type->removeType($negated_type);
|
||||
|
||||
if (empty($existing_var_type->types)) {
|
||||
if (!$existing_var_type->from_docblock) {
|
||||
if (!$existing_var_type->from_docblock
|
||||
&& ($key !== '$this' || !($statements_checker->getSource()->getSource() instanceof TraitChecker))
|
||||
) {
|
||||
if ($key && $code_location) {
|
||||
if (IssueBuffer::accepts(
|
||||
new FailedTypeResolution('Cannot resolve types for ' . $key, $code_location),
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace Psalm;
|
||||
|
||||
use Psalm\Checker\FileChecker;
|
||||
use Psalm\Checker\StatementsChecker;
|
||||
use Psalm\Type\Union;
|
||||
|
||||
class Context
|
||||
@ -273,14 +273,14 @@ class Context
|
||||
/**
|
||||
* @param string $remove_var_id
|
||||
* @param Union|null $new_type
|
||||
* @param FileChecker|null $file_checker
|
||||
* @param ?StatementsChecker $statements_checker
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeVarFromConflictingClauses(
|
||||
$remove_var_id,
|
||||
Union $new_type = null,
|
||||
FileChecker $file_checker = null
|
||||
StatementsChecker $statements_checker = null
|
||||
) {
|
||||
$clauses_to_keep = [];
|
||||
|
||||
@ -293,7 +293,7 @@ class Context
|
||||
$clause->possibilities[$remove_var_id] === [$new_type_string]
|
||||
) {
|
||||
$clauses_to_keep[] = $clause;
|
||||
} elseif ($file_checker &&
|
||||
} elseif ($statements_checker &&
|
||||
$new_type &&
|
||||
!$new_type->isMixed()
|
||||
) {
|
||||
@ -313,7 +313,7 @@ class Context
|
||||
$type,
|
||||
clone $new_type,
|
||||
null,
|
||||
$file_checker,
|
||||
$statements_checker,
|
||||
null,
|
||||
[],
|
||||
$failed_reconciliation
|
||||
@ -342,7 +342,7 @@ class Context
|
||||
* @param string $remove_var_id
|
||||
* @param \Psalm\Type\Union|null $existing_type
|
||||
* @param \Psalm\Type\Union|null $new_type
|
||||
* @param FileChecker|null $file_checker
|
||||
* @param ?StatementsChecker $statements_checker
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@ -350,7 +350,7 @@ class Context
|
||||
$remove_var_id,
|
||||
Union $existing_type = null,
|
||||
Union $new_type = null,
|
||||
FileChecker $file_checker = null
|
||||
StatementsChecker $statements_checker = null
|
||||
) {
|
||||
if (!$existing_type && isset($this->vars_in_scope[$remove_var_id])) {
|
||||
$existing_type = $this->vars_in_scope[$remove_var_id];
|
||||
@ -363,7 +363,7 @@ class Context
|
||||
$this->removeVarFromConflictingClauses(
|
||||
$remove_var_id,
|
||||
$existing_type->isMixed() ? null : $new_type,
|
||||
$file_checker
|
||||
$statements_checker
|
||||
);
|
||||
|
||||
if ($existing_type->hasArray() || $existing_type->isMixed()) {
|
||||
|
@ -259,6 +259,18 @@ class TraitTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'instanceOfTraitUser' => [
|
||||
'<?php
|
||||
trait T {
|
||||
public function f() : void {
|
||||
if ($this instanceof A) { }
|
||||
}
|
||||
}
|
||||
|
||||
class A {
|
||||
use T;
|
||||
}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ namespace Psalm\Tests;
|
||||
|
||||
use Psalm\Checker\AlgebraChecker;
|
||||
use Psalm\Checker\FileChecker;
|
||||
use Psalm\Checker\StatementsChecker;
|
||||
use Psalm\Checker\TypeChecker;
|
||||
use Psalm\Clause;
|
||||
use Psalm\Context;
|
||||
@ -16,6 +17,9 @@ class TypeReconciliationTest extends TestCase
|
||||
/** @var FileChecker */
|
||||
protected $file_checker;
|
||||
|
||||
/** @var StatementsChecker */
|
||||
protected $statements_checker;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
@ -25,6 +29,7 @@ class TypeReconciliationTest extends TestCase
|
||||
|
||||
$this->file_checker = new FileChecker('somefile.php', $this->project_checker);
|
||||
$this->file_checker->context = new Context();
|
||||
$this->statements_checker = new StatementsChecker($this->file_checker);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,7 +47,7 @@ class TypeReconciliationTest extends TestCase
|
||||
$type,
|
||||
Type::parseString($string),
|
||||
null,
|
||||
$this->file_checker
|
||||
$this->statements_checker
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
|
Loading…
Reference in New Issue
Block a user