diff --git a/README.md b/README.md index b8cbf96..ba0f53f 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,9 @@ These are the available attributes and their corresponding PHPDoc annotations: | Attribute | PHPDoc Annotations | |-------------------------------------------------------------------------------------------------------------------|--------------------| +| [Assert](https://github.com/php-static-analysis/attributes/blob/main/doc/Assert.md) | `@assert` | +| [AssertIfFalse](https://github.com/php-static-analysis/attributes/blob/main/doc/AssertIfFalse.md) | `@assert-if-false` | +| [AssertIfTrue](https://github.com/php-static-analysis/attributes/blob/main/doc/AssertIfTrue.md) | `@assert-if-true` | | [DefineType](https://github.com/php-static-analysis/attributes/blob/main/doc/DefineType.md) | `@type` | | [Deprecated](https://github.com/php-static-analysis/attributes/blob/main/doc/Deprecated.md) | `@deprecated` | | [Immmutable](https://github.com/php-static-analysis/attributes/blob/main/doc/Immmutable.md) | `@immmutable` | @@ -160,7 +163,7 @@ These are the available attributes and their corresponding PHPDoc annotations: ### Location of Param and ParamOut attributes -By default `Param` and `ParamOut `attributes are added on the method/function where the `@param` or `@param-out` annotation was located. It is possible to instead add them on the corresponding parameter in the function. To activate this option, add this code to your configuration: +By default `Param` and `ParamOut` attributes are added on the method/function where the `@param` or `@param-out` annotation was located. It is possible to instead add them on the corresponding parameter in the function. To activate this option, add this code to your configuration: ```php use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector; @@ -177,6 +180,25 @@ return RectorConfig::configure() ); ``` +### Location of Assert, AssertIfFalse and AssertIfTrue attributes + +By default `Assert`, `AssertIfFalse` and `AssertIfTrue` attributes are added on the method/function where the `@assert`, `@assert-if-false` or `@assert-if-true` annotation was located. It is possible to instead add them on the corresponding parameter in the function. To activate this option, add this code to your configuration: + +```php +use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector; +use Rector\Config\RectorConfig; +... + +return RectorConfig::configure() + ... + ->withConfiguredRule( + AnnotationsToAttributesRector::class, + [ + 'addAssertAttributeOnParameters' => true, + ] + ); +``` + ### Attribute to use for the return type of methods and functions By default `Returns` attributes are added to define the return type of methods/functions. It is possible to use the `Type` attribute instead. To activate this option, add this code to your configuration: @@ -215,6 +237,25 @@ return RectorConfig::configure() ); ``` +### Attribute to use for the definition of types for classes + +By default `DefineType` attributes are added to define a type for a class. It is possible to use the `Type` attribute instead. To activate this option, add this code to your configuration: + +```php +use PhpStaticAnalysis\RectorRule\AnnotationsToAttributesRector; +use Rector\Config\RectorConfig; +... + +return RectorConfig::configure() + ... + ->withConfiguredRule( + AnnotationsToAttributesRector::class, + [ + 'useTypeAttributeForTypeClassAnnotation' => true, + ] + ); +``` + ## Sponsor this project If you would like to support the development of this project, please consider [sponsoring me](https://github.com/sponsors/carlos-granados) diff --git a/composer.json b/composer.json index ac2c3d8..1645519 100644 --- a/composer.json +++ b/composer.json @@ -27,8 +27,8 @@ "prefer-stable": true, "require": { "php": ">=8.0", - "php-static-analysis/attributes": "^0.3.0 || dev-main", - "php-static-analysis/node-visitor": "^0.3.0 || dev-main", + "php-static-analysis/attributes": "^0.3.1 || dev-main", + "php-static-analysis/node-visitor": "^0.3.1 || dev-main", "rector/rector": "^0.19 || ^1.0" }, "require-dev": { diff --git a/config/sets/php-static-analysis-annotations-to-attributes.php b/config/sets/php-static-analysis-annotations-to-attributes.php index 207df60..e9bb75b 100644 --- a/config/sets/php-static-analysis-annotations-to-attributes.php +++ b/config/sets/php-static-analysis-annotations-to-attributes.php @@ -2,6 +2,9 @@ declare(strict_types=1); +use PhpStaticAnalysis\Attributes\Assert; +use PhpStaticAnalysis\Attributes\AssertIfFalse; +use PhpStaticAnalysis\Attributes\AssertIfTrue; use PhpStaticAnalysis\Attributes\DefineType; use PhpStaticAnalysis\Attributes\Deprecated; use PhpStaticAnalysis\Attributes\Immutable; @@ -37,6 +40,9 @@ ->withConfiguredRule( AnnotationsToAttributesRector::class, [ + new AnnotationToAttribute('assert', Assert::class), + new AnnotationToAttribute('assert_if_false', AssertIfFalse::class), + new AnnotationToAttribute('assert_if_true', AssertIfTrue::class), new AnnotationToAttribute('deprecated', Deprecated::class), new AnnotationToAttribute('extends', TemplateExtends::class), new AnnotationToAttribute('immutable', Immutable::class), @@ -69,6 +75,7 @@ new AnnotationToAttribute('use', TemplateUse::class), new AnnotationToAttribute('var', Type::class), 'addParamAttributeOnParameters' => false, + 'addAssertAttributeOnParameters' => false, 'useTypeAttributeForReturnAnnotation' => false, 'usePropertyAttributeForVarAnnotation' => false, 'excludeAnnotations' => [], diff --git a/src/AnnotationsToAttributesRector.php b/src/AnnotationsToAttributesRector.php index a78fd98..16e8b0c 100644 --- a/src/AnnotationsToAttributesRector.php +++ b/src/AnnotationsToAttributesRector.php @@ -21,6 +21,9 @@ use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Trait_; use PhpParser\Node\Stmt\TraitUse; +use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagMethodValueNode; +use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagPropertyValueNode; +use PHPStan\PhpDocParser\Ast\PhpDoc\AssertTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\DeprecatedTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\ExtendsTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode; @@ -42,6 +45,9 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\UsesTagValueNode; use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode; use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; +use PhpStaticAnalysis\Attributes\Assert; +use PhpStaticAnalysis\Attributes\AssertIfFalse; +use PhpStaticAnalysis\Attributes\AssertIfTrue; use PhpStaticAnalysis\Attributes\Param; use PhpStaticAnalysis\Attributes\ParamOut; use PhpStaticAnalysis\Attributes\Property; @@ -69,6 +75,8 @@ final class AnnotationsToAttributesRector extends AbstractRector implements Conf private bool $addParamAttributeOnParameters = false; + private bool $addAssertAttributeOnParameters = false; + private bool $useTypeAttributeForReturnAnnotation = false; private bool $usePropertyAttributeForVarAnnotation = false; @@ -148,6 +156,8 @@ public function configure(array $configuration): void $this->annotationsToAttributes[$tag] = $value; } elseif (is_bool($value) && $key == 'addParamAttributeOnParameters') { $this->addParamAttributeOnParameters = $value; + } elseif (is_bool($value) && $key == 'addAssertAttributeOnParameters') { + $this->addAssertAttributeOnParameters = $value; } elseif (is_bool($value) && $key == 'useTypeAttributeForReturnAnnotation') { $this->useTypeAttributeForReturnAnnotation = $value; } elseif (is_bool($value) && $key == 'usePropertyAttributeForVarAnnotation') { @@ -210,12 +220,17 @@ public function refactor(Node $node): ?Node $this->attributeGroupNamedArgumentManipulator->decorate($attributeGroups); } - if ($this->addParamAttributeOnParameters && + if (($this->addParamAttributeOnParameters || $this->addAssertAttributeOnParameters) && ($node instanceof ClassMethod || $node instanceof Function_)) { foreach ($attributeGroups as $attrKey => $attributeGroup) { foreach ($attributeGroup->attrs as $key => $attribute) { $attributeName = (string)$attribute->name; - if ($attributeName === Param::class || $attributeName == ParamOut::class) { + if ( + (($attributeName === Param::class || $attributeName === ParamOut::class) + && $this->addParamAttributeOnParameters) || + (($attributeName === Assert::class || $attributeName === AssertIfFalse::class || $attributeName === AssertIfTrue::class) + && $this->addAssertAttributeOnParameters) + ) { $args = $attribute->args; if (isset($args[0])) { $arg = $args[0]; @@ -373,6 +388,33 @@ private function processAnnotations(PhpDocInfo $phpDocInfo): array ) ]; break; + case $tagValueNode instanceof AssertTagValueNode: + case $tagValueNode instanceof AssertTagPropertyValueNode: + case $tagValueNode instanceof AssertTagMethodValueNode: + $type = (string)($tagValueNode->type); + if ($tagValueNode->isNegated) { + $type = '!' . $type; + } + if ($tagValueNode->isEquality) { + $type = '=' . $type; + } + if ($tagValueNode instanceof AssertTagValueNode) { + $args = [ + new Arg( + value: new String_($type), + name: new Identifier(substr($tagValueNode->parameter, 1)) + ) + ]; + } else { + if ($tagValueNode instanceof AssertTagPropertyValueNode) { + $type .= ' ' . $tagValueNode->parameter . '->' . $tagValueNode->property; + } else { + $type .= ' ' . $tagValueNode->parameter . '->' . $tagValueNode->method . '()'; + } + $args = [new Arg(new String_($type))]; + } + $attributeComment = $tagValueNode->description; + break; default: continue 2; } diff --git a/tests/AnnotationsToAttributesWithAssertOnParamRectorTest.php b/tests/AnnotationsToAttributesWithAssertOnParamRectorTest.php new file mode 100644 index 0000000..6b95dd6 --- /dev/null +++ b/tests/AnnotationsToAttributesWithAssertOnParamRectorTest.php @@ -0,0 +1,31 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + yield [__DIR__ . '/SpecialFixture/AssertAttributeTestWithAssertOnParam.php.inc']; + yield [__DIR__ . '/SpecialFixture/AssertIfFalseAttributeTestWithAssertOnParam.php.inc']; + yield [__DIR__ . '/SpecialFixture/AssertIfTrueAttributeTestWithAssertOnParam.php.inc']; + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured-rule-with-assert-on-param.php'; + } +} diff --git a/tests/Fixture/AssertAttributeTest.php.inc b/tests/Fixture/AssertAttributeTest.php.inc new file mode 100644 index 0000000..6c759f9 --- /dev/null +++ b/tests/Fixture/AssertAttributeTest.php.inc @@ -0,0 +1,251 @@ +item + */ + public function checkPropertyName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $this->getName() + */ + public function checkMethodName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @codeCoverageIgnore + * @phpstan-assert string $name + */ + public function checkMoreNames($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name + */ + #[Returns('string')] + public function checkAnotherName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name1 + * @phpstan-assert string $name2 + */ + public function checkTwoNames($name1, $name2) + { + if (!is_string($name1) && !is_string($name2)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name2 + */ + #[Assert(name1: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + if (!is_string($name1) && !is_string($name2)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name the name of the user + */ + public function checkUserName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @psalm-assert string $name + */ + public function checkPsalmName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } +} + +/** + * @phpstan-assert string $name + */ +function checkName($name) +{ + if (!is_string($name)) { + throw new Exception(); + } +} + +?> +----- +item')] + public function checkPropertyName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + #[Assert('string $this->getName()')] + public function checkMethodName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @codeCoverageIgnore + */ + #[Assert(name: 'string')] + public function checkMoreNames($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + #[Returns('string')] + #[Assert(name: 'string')] + public function checkAnotherName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + #[Assert(name1: 'string')] + #[Assert(name2: 'string')] + public function checkTwoNames($name1, $name2) + { + if (!is_string($name1) && !is_string($name2)) { + throw new Exception(); + } + } + + #[Assert(name1: 'string')] + #[Assert(name2: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + if (!is_string($name1) && !is_string($name2)) { + throw new Exception(); + } + } + + #[Assert(name: 'string')] // the name of the user + public function checkUserName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + #[Assert(name: 'string')] + public function checkPsalmName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } +} + +#[Assert(name: 'string')] +function checkName($name) +{ + if (!is_string($name)) { + throw new Exception(); + } +} + +?> diff --git a/tests/Fixture/AssertIfFalseAttributeTest.php.inc b/tests/Fixture/AssertIfFalseAttributeTest.php.inc new file mode 100644 index 0000000..21c84de --- /dev/null +++ b/tests/Fixture/AssertIfFalseAttributeTest.php.inc @@ -0,0 +1,203 @@ +item + */ + public function checkPropertyName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-false string $this->getName() + */ + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + * @phpstan-assert-if-false string $name + */ + public function checkMoreNames($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-false string $name + */ + #[Returns('string')] + public function checkAnotherName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-false string $name1 + * @phpstan-assert-if-false string $name2 + */ + public function checkTwoNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @phpstan-assert-if-false string $name2 + */ + #[AssertIfFalse(name1: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @phpstan-assert-if-false string $name the name of the user + */ + public function checkUserName($name) + { + return !is_string($name); + } + + /** + * @psalm-assert-if-false string $name + */ + public function checkPsalmName($name) + { + return !is_string($name); + } +} + +/** + * @phpstan-assert-if-false string $name + */ +function checkName($name) +{ + return !is_string($name); +} + +?> +----- +item')] + public function checkPropertyName($name) + { + return !is_string($name); + } + + #[AssertIfFalse('string $this->getName()')] + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + */ + #[AssertIfFalse(name: 'string')] + public function checkMoreNames($name) + { + return !is_string($name); + } + + #[Returns('string')] + #[AssertIfFalse(name: 'string')] + public function checkAnotherName($name) + { + return !is_string($name); + } + + #[AssertIfFalse(name1: 'string')] + #[AssertIfFalse(name2: 'string')] + public function checkTwoNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + #[AssertIfFalse(name1: 'string')] + #[AssertIfFalse(name2: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + #[AssertIfFalse(name: 'string')] // the name of the user + public function checkUserName($name) + { + return !is_string($name); + } + + #[AssertIfFalse(name: 'string')] + public function checkPsalmName($name) + { + return !is_string($name); + } +} + +#[AssertIfFalse(name: 'string')] +function checkName($name) +{ + return !is_string($name); +} + +?> diff --git a/tests/Fixture/AssertIfTrueAttributeTest.php.inc b/tests/Fixture/AssertIfTrueAttributeTest.php.inc new file mode 100644 index 0000000..80dff6e --- /dev/null +++ b/tests/Fixture/AssertIfTrueAttributeTest.php.inc @@ -0,0 +1,203 @@ +item + */ + public function checkPropertyName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-true string $this->getName() + */ + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + * @phpstan-assert-if-true string $name + */ + public function checkMoreNames($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-true string $name + */ + #[Returns('string')] + public function checkAnotherName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-true string $name1 + * @phpstan-assert-if-true string $name2 + */ + public function checkTwoNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @phpstan-assert-if-true string $name2 + */ + #[AssertIfTrue(name1: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @phpstan-assert-if-true string $name the name of the user + */ + public function checkUserName($name) + { + return !is_string($name); + } + + /** + * @psalm-assert-if-true string $name + */ + public function checkPsalmName($name) + { + return !is_string($name); + } +} + +/** + * @phpstan-assert-if-true string $name + */ +function checkName($name) +{ + return !is_string($name); +} + +?> +----- +item')] + public function checkPropertyName($name) + { + return !is_string($name); + } + + #[AssertIfTrue('string $this->getName()')] + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + */ + #[AssertIfTrue(name: 'string')] + public function checkMoreNames($name) + { + return !is_string($name); + } + + #[Returns('string')] + #[AssertIfTrue(name: 'string')] + public function checkAnotherName($name) + { + return !is_string($name); + } + + #[AssertIfTrue(name1: 'string')] + #[AssertIfTrue(name2: 'string')] + public function checkTwoNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + #[AssertIfTrue(name1: 'string')] + #[AssertIfTrue(name2: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + #[AssertIfTrue(name: 'string')] // the name of the user + public function checkUserName($name) + { + return !is_string($name); + } + + #[AssertIfTrue(name: 'string')] + public function checkPsalmName($name) + { + return !is_string($name); + } +} + +#[AssertIfTrue(name: 'string')] +function checkName($name) +{ + return !is_string($name); +} + +?> diff --git a/tests/SpecialFixture/AssertAttributeTestWithAssertOnParam.php.inc b/tests/SpecialFixture/AssertAttributeTestWithAssertOnParam.php.inc new file mode 100644 index 0000000..fb322d5 --- /dev/null +++ b/tests/SpecialFixture/AssertAttributeTestWithAssertOnParam.php.inc @@ -0,0 +1,233 @@ +item + */ + public function checkPropertyName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $this->getName() + */ + public function checkMethodName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @codeCoverageIgnore + * @phpstan-assert string $name + */ + public function checkMoreNames($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name + */ + #[Returns('string')] + public function checkAnotherName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name1 + * @phpstan-assert string $name2 + */ + public function checkTwoNames($name1, $name2) + { + if (!is_string($name1) || !is_string($name2)) { + throw new Exception(); + } + } + + /** + * @phpstan-assert string $name2 + */ + #[Assert(name1: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + if (!is_string($name1) || !is_string($name2)) { + throw new Exception(); + } + } + + /** + * @psalm-assert string $name + */ + public function checkPsalmName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } +} + +/** + * @phpstan-assert string $name + */ +function checkName($name) +{ + if (!is_string($name)) { + throw new Exception(); + } +} + +?> +----- +item')] + public function checkPropertyName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + #[Assert('string $this->getName()')] + public function checkMethodName($name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + /** + * @codeCoverageIgnore + */ + public function checkMoreNames(#[Assert('string')] + $name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + #[Returns('string')] + public function checkAnotherName(#[Assert('string')] + $name) + { + if (!is_string($name)) { + throw new Exception(); + } + } + + public function checkTwoNames(#[Assert('string')] + $name1, #[Assert('string')] + $name2) + { + if (!is_string($name1) || !is_string($name2)) { + throw new Exception(); + } + } + + #[Assert(name1: 'string')] + public function checkTwoMoreNames($name1, #[Assert('string')] + $name2) + { + if (!is_string($name1) || !is_string($name2)) { + throw new Exception(); + } + } + + public function checkPsalmName(#[Assert('string')] + $name) + { + if (!is_string($name)) { + throw new Exception(); + } + } +} + +function checkName(#[Assert('string')] +$name) +{ + if (!is_string($name)) { + throw new Exception(); + } +} + +?> diff --git a/tests/SpecialFixture/AssertIfFalseAttributeTestWithAssertOnParam.php.inc b/tests/SpecialFixture/AssertIfFalseAttributeTestWithAssertOnParam.php.inc new file mode 100644 index 0000000..d6a288d --- /dev/null +++ b/tests/SpecialFixture/AssertIfFalseAttributeTestWithAssertOnParam.php.inc @@ -0,0 +1,189 @@ +item + */ + public function checkPropertyName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-false string $this->getName() + */ + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + * @phpstan-assert-if-false string $name + */ + public function checkMoreNames($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-false string $name + */ + #[Returns('string')] + public function checkAnotherName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-false string $name1 + * @phpstan-assert-if-false string $name2 + */ + public function checkTwoNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @phpstan-assert-if-false string $name2 + */ + #[AssertIfFalse(name1: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @psalm-assert-if-false string $name + */ + public function checkPsalmName($name) + { + return !is_string($name); + } +} + +/** + * @phpstan-assert-if-false string $name + */ +function checkName($name) +{ + return !is_string($name); +} + +?> +----- +item')] + public function checkPropertyName($name) + { + return !is_string($name); + } + + #[AssertIfFalse('string $this->getName()')] + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + */ + public function checkMoreNames(#[AssertIfFalse('string')] + $name) + { + return !is_string($name); + } + + #[Returns('string')] + public function checkAnotherName(#[AssertIfFalse('string')] + $name) + { + return !is_string($name); + } + + public function checkTwoNames(#[AssertIfFalse('string')] + $name1, #[AssertIfFalse('string')] + $name2) + { + return !is_string($name1) || !is_string($name2); + } + + #[AssertIfFalse(name1: 'string')] + public function checkTwoMoreNames($name1, #[AssertIfFalse('string')] + $name2) + { + return !is_string($name1) || !is_string($name2); + } + + public function checkPsalmName(#[AssertIfFalse('string')] + $name) + { + return !is_string($name); + } +} + +function checkName(#[AssertIfFalse('string')] +$name) +{ + return !is_string($name); +} + +?> diff --git a/tests/SpecialFixture/AssertIfTrueAttributeTestWithAssertOnParam.php.inc b/tests/SpecialFixture/AssertIfTrueAttributeTestWithAssertOnParam.php.inc new file mode 100644 index 0000000..3109f66 --- /dev/null +++ b/tests/SpecialFixture/AssertIfTrueAttributeTestWithAssertOnParam.php.inc @@ -0,0 +1,189 @@ +item + */ + public function checkPropertyName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-true string $this->getName() + */ + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + * @phpstan-assert-if-true string $name + */ + public function checkMoreNames($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-true string $name + */ + #[Returns('string')] + public function checkAnotherName($name) + { + return !is_string($name); + } + + /** + * @phpstan-assert-if-true string $name1 + * @phpstan-assert-if-true string $name2 + */ + public function checkTwoNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @phpstan-assert-if-true string $name2 + */ + #[AssertIfTrue(name1: 'string')] + public function checkTwoMoreNames($name1, $name2) + { + return !is_string($name1) || !is_string($name2); + } + + /** + * @psalm-assert-if-true string $name + */ + public function checkPsalmName($name) + { + return !is_string($name); + } +} + +/** + * @phpstan-assert-if-true string $name + */ +function checkName($name) +{ + return !is_string($name); +} + +?> +----- +item')] + public function checkPropertyName($name) + { + return !is_string($name); + } + + #[AssertIfTrue('string $this->getName()')] + public function checkMethodName($name) + { + return !is_string($name); + } + + /** + * @codeCoverageIgnore + */ + public function checkMoreNames(#[AssertIfTrue('string')] + $name) + { + return !is_string($name); + } + + #[Returns('string')] + public function checkAnotherName(#[AssertIfTrue('string')] + $name) + { + return !is_string($name); + } + + public function checkTwoNames(#[AssertIfTrue('string')] + $name1, #[AssertIfTrue('string')] + $name2) + { + return !is_string($name1) || !is_string($name2); + } + + #[AssertIfTrue(name1: 'string')] + public function checkTwoMoreNames($name1, #[AssertIfTrue('string')] + $name2) + { + return !is_string($name1) || !is_string($name2); + } + + public function checkPsalmName(#[AssertIfTrue('string')] + $name) + { + return !is_string($name); + } +} + +function checkName(#[AssertIfTrue('string')] +$name) +{ + return !is_string($name); +} + +?> diff --git a/tests/config/configured-rule-with-assert-on-param.php b/tests/config/configured-rule-with-assert-on-param.php new file mode 100644 index 0000000..3872cec --- /dev/null +++ b/tests/config/configured-rule-with-assert-on-param.php @@ -0,0 +1,19 @@ +withSets([ + PhpStaticAnalysisSetList::ANNOTATIONS_TO_ATTRIBUTES + ]) + ->withConfiguredRule( + AnnotationsToAttributesRector::class, + [ + 'addAssertAttributeOnParameters' => true, + ] + ) + ->withImportNames();