1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 13:51:54 +01:00

Merge pull request #7251 from klimick/run-if-this-is-before-this-out

Checking `psalm-if-this-is` before applying `psalm-this-out`
This commit is contained in:
orklah 2021-12-30 21:20:31 +01:00 committed by GitHub
commit 0ec8dd260d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 28 deletions

View File

@ -22,6 +22,7 @@ use Psalm\Internal\Type\Comparator\TypeComparisonResult;
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\TypeExpander;
use Psalm\Issue\IfThisIsMismatch;
use Psalm\Issue\InvalidPropertyAssignmentValue;
use Psalm\Issue\MixedPropertyTypeCoercion;
use Psalm\Issue\PossiblyInvalidPropertyAssignmentValue;
@ -270,6 +271,25 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer
}
if ($method_storage) {
$class_type = new Union([$lhs_type_part]);
if ($method_storage->if_this_is_type
&& !UnionTypeComparator::isContainedBy(
$codebase,
$class_type,
$method_storage->if_this_is_type
)
) {
IssueBuffer::maybeAdd(
new IfThisIsMismatch(
'Class type must be ' . $method_storage->if_this_is_type->getId()
. ' current type ' . $class_type->getId(),
new CodeLocation($source, $stmt->name)
),
$statements_analyzer->getSuppressedIssues()
);
}
if ($method_storage->self_out_type && $lhs_var_id) {
$self_out_candidate = clone $method_storage->self_out_type;

View File

@ -11,9 +11,6 @@ use Psalm\Internal\Analyzer\Statements\Expression\CallAnalyzer;
use Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\MethodIdentifier;
use Psalm\Internal\Type\Comparator\UnionTypeComparator;
use Psalm\Issue\IfThisIsMismatch;
use Psalm\Issue\InvalidMethodCall;
use Psalm\Issue\InvalidScope;
use Psalm\Issue\NullReference;
@ -423,30 +420,6 @@ class MethodCallAnalyzer extends CallAnalyzer
$context->vars_in_scope[$lhs_var_id] = $class_type;
}
if ($lhs_var_id) {
$method_id = MethodIdentifier::wrap($result->existent_method_ids[0]);
// TODO: When should a method have a storage?
if ($codebase->methods->hasStorage($method_id)) {
$storage = $codebase->methods->getStorage($method_id);
if ($storage->if_this_is_type
&& !UnionTypeComparator::isContainedBy(
$codebase,
$class_type,
$storage->if_this_is_type
)
) {
IssueBuffer::maybeAdd(
new IfThisIsMismatch(
'Class is not ' . (string) $storage->if_this_is_type
. ' as required by psalm-if-this-is',
new CodeLocation($source, $stmt->name)
),
$statements_analyzer->getSuppressedIssues()
);
}
}
}
return true;
}

View File

@ -111,7 +111,29 @@ class IfThisIsTest extends TestCase
$f = new F();
$f->test();
'
]
],
'ifThisIsAndThisOutAtTheSameTime' => [
'<?php
/**
* @template T of string
*/
final class App
{
/**
* @psalm-if-this-is App<"idle">
* @psalm-this-out App<"started">
*/
public function start(): void
{
throw new RuntimeException("???");
}
}
/** @var App<"idle"> */
$app = new App();
$app->start();
'
],
];
}