Skip to content

Commit 8edfde0

Browse files
axlonondrejmirtes
authored andcommitted
Add support for constructor assertions
1 parent fc68c0f commit 8edfde0

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

src/Analyser/TypeSpecifier.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,34 @@ public function specifyTypesInCondition(
866866

867867
$nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
868868
return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope));
869+
} elseif (
870+
$expr instanceof Expr\New_
871+
&& $expr->class instanceof Name
872+
&& $this->reflectionProvider->hasClass($expr->class->toString())
873+
) {
874+
$classReflection = $this->reflectionProvider->getClass($expr->class->toString());
875+
876+
if ($classReflection->hasConstructor()) {
877+
$methodReflection = $classReflection->getConstructor();
878+
$asserts = $methodReflection->getAsserts();
879+
880+
if ($asserts->getAll() !== []) {
881+
$parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants());
882+
883+
$asserts = $asserts->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes(
884+
$type,
885+
$parametersAcceptor->getResolvedTemplateTypeMap(),
886+
$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(),
887+
TemplateTypeVariance::createInvariant(),
888+
));
889+
890+
$specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope);
891+
892+
if ($specifiedTypes !== null) {
893+
return $specifiedTypes;
894+
}
895+
}
896+
}
869897
} elseif (!$context->null()) {
870898
return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
871899
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,7 @@ public function dataFileAsserts(): iterable
12111211

12121212
yield from $this->gatherAssertTypes(__DIR__ . '/data/array-offset-unset.php');
12131213

1214+
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-constructor.php');
12141215
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-docblock.php');
12151216
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-empty.php');
12161217
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-method.php');
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace AssertConstructor;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Person
8+
{
9+
/**
10+
* @phpstan-assert non-empty-string $firstName
11+
*/
12+
public function __construct(
13+
public string $firstName,
14+
) {
15+
assert($firstName !== '');
16+
}
17+
}
18+
19+
function (string $firstName) {
20+
new Person($firstName);
21+
assertType('non-empty-string', $firstName);
22+
};

0 commit comments

Comments
 (0)