Skip to content

Commit

Permalink
Add support for constructor assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
axlon committed Feb 29, 2024
1 parent fc68c0f commit 9096a80
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,34 @@ public function specifyTypesInCondition(

$nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope));
} elseif (
$expr instanceof Expr\New_
&& $expr->class instanceof Name
&& $this->reflectionProvider->hasClass($expr->class->toString())
) {
$classReflection = $this->reflectionProvider->getClass($expr->class->toString());

if ($classReflection->hasConstructor()) {
$methodReflection = $classReflection->getConstructor();
$asserts = $methodReflection->getAsserts();

if ($asserts->getAll() !== []) {
$parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $methodReflection->getVariants(), $methodReflection->getNamedArgumentsVariants());

$asserts = $asserts->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes(
$type,
$parametersAcceptor->getResolvedTemplateTypeMap(),
$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(),
TemplateTypeVariance::createInvariant(),
));

$specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope);

if ($specifiedTypes !== null) {
return $specifiedTypes;
}
}
}
} elseif (!$context->null()) {
return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
}
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,7 @@ public function dataFileAsserts(): iterable

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

yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-constructor.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-docblock.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-empty.php');
yield from $this->gatherAssertTypes(__DIR__ . '/data/assert-method.php');
Expand Down
22 changes: 22 additions & 0 deletions tests/PHPStan/Analyser/data/assert-constructor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace AssertConstructor;

use function PHPStan\Testing\assertType;

class Person
{
/**
* @phpstan-assert non-empty-string $firstName
*/
public function __construct(
public string $firstName,
) {
assert($firstName !== '');
}
}

function (string $firstName) {
new Person($firstName);
assertType('non-empty-string', $firstName);
};

0 comments on commit 9096a80

Please sign in to comment.