Skip to content

Revert non-empty-string changes and add regression test #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,10 @@ This extension specifies types of values passed to:
* `Assert::methodExists`
* `Assert::propertyExists`
* `Assert::isArrayAccessible`
* `Assert::contains`
* `Assert::startsWith`
* `Assert::startsWithLetter`
* `Assert::endsWith`
* `Assert::unicodeLetters`
* `Assert::alpha`
* `Assert::digits`
* `Assert::alnum`
* `Assert::lower`
* `Assert::upper`
* `Assert::length`
* `Assert::minLength`
* `Assert::maxLength`
* `Assert::lengthBetween`
* `Assert::uuid`
* `Assert::ip`
* `Assert::ipv4`
* `Assert::ipv6`
* `Assert::email`
* `Assert::notWhitespaceOnly`
* `nullOr*` and `all*` variants of the above methods


Expand Down
87 changes: 12 additions & 75 deletions src/Type/WebMozartAssert/AssertTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,6 @@
class AssertTypeSpecifyingExtension implements StaticMethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
{

private const ASSERTIONS_RESULTING_IN_NON_EMPTY_STRING = [
'stringNotEmpty',
'startsWithLetter',
'unicodeLetters',
'alpha',
'digits',
'alnum',
'lower',
'upper',
'uuid',
'ip',
'ipv4',
'ipv6',
'email',
'notWhitespaceOnly',
];

/** @var \Closure[] */
private static $resolvers;

Expand All @@ -67,10 +50,6 @@ public function isStaticMethodSupported(
TypeSpecifierContext $context
): bool
{
if (in_array($staticMethodReflection->getName(), self::ASSERTIONS_RESULTING_IN_NON_EMPTY_STRING, true)) {
return true;
}

if (substr($staticMethodReflection->getName(), 0, 6) === 'allNot') {
$methods = [
'allNotInstanceOf' => 2,
Expand Down Expand Up @@ -165,11 +144,6 @@ private static function createExpression(
): ?\PhpParser\Node\Expr
{
$trimmedName = self::trimName($name);

if (in_array($trimmedName, self::ASSERTIONS_RESULTING_IN_NON_EMPTY_STRING, true)) {
return self::createIsNonEmptyStringExpression($args);
}

$resolvers = self::getExpressionResolvers();
$resolver = $resolvers[$trimmedName];
$expression = $resolver($scope, ...$args);
Expand Down Expand Up @@ -221,6 +195,18 @@ private static function getExpressionResolvers(): array
[$value]
);
},
'stringNotEmpty' => function (Scope $scope, Arg $value): \PhpParser\Node\Expr {
return new BooleanAnd(
new \PhpParser\Node\Expr\FuncCall(
new \PhpParser\Node\Name('is_string'),
[$value]
),
new NotIdentical(
$value->value,
new String_('')
)
);
},
'float' => function (Scope $scope, Arg $value): \PhpParser\Node\Expr {
return new \PhpParser\Node\Expr\FuncCall(
new \PhpParser\Node\Name('is_float'),
Expand Down Expand Up @@ -486,27 +472,6 @@ private static function getExpressionResolvers(): array
)
);
},
'contains' => function (Scope $scope, Arg $value, Arg $subString): \PhpParser\Node\Expr {
if ($scope->getType($subString->value)->isNonEmptyString()->yes()) {
return self::createIsNonEmptyStringExpression([$value]);
}

return self::createIsStringExpression([$value]);
},
'startsWith' => function (Scope $scope, Arg $value, Arg $prefix): \PhpParser\Node\Expr {
if ($scope->getType($prefix->value)->isNonEmptyString()->yes()) {
return self::createIsNonEmptyStringExpression([$value]);
}

return self::createIsStringExpression([$value]);
},
'endsWith' => function (Scope $scope, Arg $value, Arg $suffix): \PhpParser\Node\Expr {
if ($scope->getType($suffix->value)->isNonEmptyString()->yes()) {
return self::createIsNonEmptyStringExpression([$value]);
}

return self::createIsStringExpression([$value]);
},
'length' => function (Scope $scope, Arg $value, Arg $length): \PhpParser\Node\Expr {
return new BooleanAnd(
new \PhpParser\Node\Expr\FuncCall(
Expand Down Expand Up @@ -709,32 +674,4 @@ private function arrayOrIterable(
);
}

/**
* @param \PhpParser\Node\Arg[] $args
*/
private static function createIsStringExpression(array $args): \PhpParser\Node\Expr
{
return new \PhpParser\Node\Expr\FuncCall(
new \PhpParser\Node\Name('is_string'),
[$args[0]]
);
}

/**
* @param \PhpParser\Node\Arg[] $args
*/
private static function createIsNonEmptyStringExpression(array $args): \PhpParser\Node\Expr
{
return new BooleanAnd(
new \PhpParser\Node\Expr\FuncCall(
new \PhpParser\Node\Name('is_string'),
[$args[0]]
),
new NotIdentical(
$args[0]->value,
new String_('')
)
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,15 @@ public function testExtension(): void
]);
}

public function testBug85(): void
{
$this->analyse([__DIR__ . '/data/bug-85.php'], []);
}

public static function getAdditionalConfigFiles(): array
{
return [
__DIR__ . '/../../../vendor/phpstan/phpstan-strict-rules/rules.neon',
__DIR__ . '/../../../extension.neon',
];
}
Expand Down
34 changes: 34 additions & 0 deletions tests/Type/WebMozartAssert/data/bug-85.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace PHPStan\Type\WebMozartAssert;

use Webmozart\Assert\Assert;

final class Bug85
{

public function foo(string $cityCode): void
{
Assert::length($cityCode, 3);
Assert::upper($cityCode);
}

/**
* @param mixed $url
*/
function bar($url): void
{
Assert::stringNotEmpty($url);
Assert::contains($url, '/');
Assert::startsWith($url, 'https://github.com/');
}

public function baz(string $s): void
{
Assert::stringNotEmpty($s);
Assert::uuid($s);
}

}
114 changes: 0 additions & 114 deletions tests/Type/WebMozartAssert/data/string.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,6 @@
class TestStrings
{

/**
* @param non-empty-string $b
*/
public function contains(string $a, string $b): void
{
Assert::contains($a, $a);
\PHPStan\Testing\assertType('string', $a);

Assert::contains($a, $b);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

/**
* @param non-empty-string $b
*/
public function startsWith(string $a, string $b): void
{
Assert::startsWith($a, $a);
\PHPStan\Testing\assertType('string', $a);

Assert::startsWith($a, $b);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function startsWithLetter(string $a): void
{
Assert::startsWithLetter($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

/**
* @param non-empty-string $b
*/
public function endsWith(string $a, string $b): void
{
Assert::endsWith($a, $a);
\PHPStan\Testing\assertType('string', $a);

Assert::endsWith($a, $b);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function length(string $a, string $b): void
{
Assert::length($a, 0);
Expand Down Expand Up @@ -91,76 +49,4 @@ public function lengthBetween(string $a, string $b, string $c, string $d): void
\PHPStan\Testing\assertType('non-empty-string', $d);
}

public function unicodeLetters($a): void
{
Assert::unicodeLetters($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function alpha($a): void
{
Assert::alpha($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function digits(string $a): void
{
Assert::digits($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function alnum(string $a): void
{
Assert::alnum($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function lower(string $a): void
{
Assert::lower($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function upper(string $a): void
{
Assert::upper($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function uuid(string $a): void
{
Assert::uuid($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function ip($a): void
{
Assert::ip($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function ipv4($a): void
{
Assert::ipv4($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function ipv6($a): void
{
Assert::ipv6($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function email($a): void
{
Assert::email($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

public function notWhitespaceOnly(string $a): void
{
Assert::notWhitespaceOnly($a);
\PHPStan\Testing\assertType('non-empty-string', $a);
}

}