diff --git a/composer.json b/composer.json index cce6ecd..08685c7 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "require": { "php": ">=8.0", "nikic/php-parser": "^4 || ^5", - "php-static-analysis/attributes": "^0.1.3 || dev-main" + "php-static-analysis/attributes": "^0.1.4 || dev-main" }, "require-dev": { "php-static-analysis/phpstan-extension": "dev-main", diff --git a/src/AttributeNodeVisitor.php b/src/AttributeNodeVisitor.php index 5909452..d09f95a 100644 --- a/src/AttributeNodeVisitor.php +++ b/src/AttributeNodeVisitor.php @@ -14,6 +14,8 @@ use PhpStaticAnalysis\Attributes\IsReadOnly; use PhpStaticAnalysis\Attributes\Param; use PhpStaticAnalysis\Attributes\Property; +use PhpStaticAnalysis\Attributes\PropertyRead; +use PhpStaticAnalysis\Attributes\PropertyWrite; use PhpStaticAnalysis\Attributes\Returns; use PhpStaticAnalysis\Attributes\Template; use PhpStaticAnalysis\Attributes\Type; @@ -38,6 +40,8 @@ class AttributeNodeVisitor extends NodeVisitorAbstract private const ALLOWED_ATTRIBUTES_PER_NODE_TYPE = [ Stmt\Class_::class => [ Property::class, + PropertyRead::class, + PropertyWrite::class, Template::class, ], Stmt\ClassConst::class => [ @@ -72,6 +76,8 @@ class AttributeNodeVisitor extends NodeVisitorAbstract 'IsReadOnly' => IsReadOnly::class, 'Param' => Param::class, 'Property' => Property::class, + 'PropertyRead' => PropertyRead::class, + 'PropertyWrite' => PropertyWrite::class, 'Returns' => Returns::class, 'Template' => Template::class, 'Type' => Type::class, @@ -88,6 +94,12 @@ class AttributeNodeVisitor extends NodeVisitorAbstract Stmt\Class_::class => 'property', Stmt\Property::class => 'var', ], + PropertyRead::class => [ + 'all' => 'property-read', + ], + PropertyWrite::class => [ + 'all' => 'property-write', + ], Returns::class => [ 'all' => 'return', ], @@ -113,6 +125,12 @@ class AttributeNodeVisitor extends NodeVisitorAbstract Stmt\Class_::class => self::ARGS_MANY_WITH_NAME, Stmt\Property::class => self::ARGS_ONE, ], + PropertyRead::class => [ + Stmt\Class_::class => self::ARGS_MANY_WITH_NAME, + ], + PropertyWrite::class => [ + Stmt\Class_::class => self::ARGS_MANY_WITH_NAME, + ], Returns::class => [ 'all' => self::ARGS_ONE, ], diff --git a/tests/AttributeNodeVisitorTest.php b/tests/AttributeNodeVisitorTest.php index 65dcdbd..a669b1c 100644 --- a/tests/AttributeNodeVisitorTest.php +++ b/tests/AttributeNodeVisitorTest.php @@ -2,33 +2,14 @@ namespace test\PhpStaticAnalysis\NodeVisitor; -use Exception; -use PhpParser\Comment\Doc; use PhpParser\Node; use PhpParser\Node\Attribute; use PhpParser\Node\AttributeGroup; use PhpParser\Node\Identifier; use PhpParser\Node\Name\FullyQualified; -use PhpStaticAnalysis\Attributes\IsReadOnly; -use PhpStaticAnalysis\Attributes\Param; -use PhpStaticAnalysis\Attributes\Property; -use PhpStaticAnalysis\Attributes\Returns; -use PhpStaticAnalysis\Attributes\Template; -use PhpStaticAnalysis\Attributes\Type; -use PhpStaticAnalysis\NodeVisitor\AttributeNodeVisitor; -use PHPUnit\Framework\TestCase; -class AttributeNodeVisitorTest extends TestCase +class AttributeNodeVisitorTest extends AttributeNodeVisitorTestBase { - private const UNTOUCHED = "/**\n * untouched\n */"; - - private AttributeNodeVisitor $nodeVisitor; - - public function setUp(): void - { - $this->nodeVisitor = new AttributeNodeVisitor(); - } - public function testDoesNotProcessUnknownNodes(): void { $node = new Node\Stmt\Use_([]); @@ -56,259 +37,4 @@ public function testDoesNotProcessAttributeNotAvailableForStmt(): void $docText = $this->getDocText($node); $this->assertEquals(self::UNTOUCHED, $docText); } - - public function testAddsReadOnlyPHPDoc(): void - { - $node = new Node\Stmt\Property(0, []); - $this->addIsReadOnlyAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @readonly\n */", $docText); - } - - public function testAddsReadOnlyPHPDocMaintainingExistingPHPDoc(): void - { - $node = new Node\Stmt\Property(0, []); - $this->setDocComment($node, self::UNTOUCHED); - $this->addIsReadOnlyAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * untouched\n * @readonly\n */", $docText); - } - - public function testAddsReturnPHPDoc(): void - { - $node = new Node\Stmt\ClassMethod('Test'); - $this->addReturnsAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @return string\n */", $docText); - } - - public function testAddsVarPHPDoc(): void - { - $node = new Node\Stmt\Property(0, []); - $this->addTypeAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @var string\n */", $docText); - } - - public function testAddsReturnPHPDocWithTypeAttribute(): void - { - $node = new Node\Stmt\ClassMethod('Test'); - $this->addTypeAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @return string\n */", $docText); - } - - public function testAddsTemplatePHPDoc(): void - { - $node = new Node\Stmt\Class_('Test'); - $this->addTemplateAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @template T\n */", $docText); - } - - public function testAddsTemplateWithTypePHPDoc(): void - { - $node = new Node\Stmt\Class_('Test'); - $this->addTemplateAttributeToNode($node, true); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @template T of Exception\n */", $docText); - } - - public function testAddsMultipleTemplatePHPDocs(): void - { - $node = new Node\Stmt\Class_('Test'); - $this->addTemplateAttributeToNode($node); - $this->addTemplateAttributeToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @template T\n * @template T\n */", $docText); - } - - public function testAddsParamPHPDoc(): void - { - $node = new Node\Stmt\ClassMethod('Test'); - $this->addParamAttributesToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @param string \$param\n */", $docText); - } - - public function testAddsSeveralParamPHPDocs(): void - { - $node = new Node\Stmt\ClassMethod('Test'); - $this->addParamAttributesToNode($node, 2); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @param string \$param\n * @param string \$param\n */", $docText); - } - - public function testAddsMultipleParamPHPDocs(): void - { - $node = new Node\Stmt\ClassMethod('Test'); - $this->addParamAttributesToNode($node); - $this->addParamAttributesToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @param string \$param\n * @param string \$param\n */", $docText); - } - - public function testAddsParamPHPDocToParam(): void - { - $node = new Node\Stmt\ClassMethod('Test'); - $this->addParamAttributeToParamNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @param string \$param\n */", $docText); - } - - public function testAddsPropertyPHPDoc(): void - { - $node = new Node\Stmt\Class_('Test'); - $this->addPropertyAttributesToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @property string \$param\n */", $docText); - } - - public function testAddsSeveralPropertyPHPDocs(): void - { - $node = new Node\Stmt\Class_('Test'); - $this->addPropertyAttributesToNode($node, 2); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @property string \$param\n * @property string \$param\n */", $docText); - } - - public function testAddsMultiplePropertyPHPDocs(): void - { - $node = new Node\Stmt\Class_('Test'); - $this->addPropertyAttributesToNode($node); - $this->addPropertyAttributesToNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @property string \$param\n * @property string \$param\n */", $docText); - } - - public function testAddsVarPHPDocForPropertyAttribute(): void - { - $node = new Node\Stmt\Property(0, []); - $this->addPropertyAttributeToPropertyNode($node); - $this->nodeVisitor->enterNode($node); - $docText = $this->getDocText($node); - $this->assertEquals("/**\n * @var string\n */", $docText); - } - - private function setDocComment(Node $node, string $text): void - { - $docComment = new Doc( - $text, - ); - $node->setDocComment($docComment); - } - - private function addIsReadOnlyAttributeToNode( - Node\Stmt\ClassMethod | Node\Stmt\Property $node - ): void { - $attributeName = new FullyQualified(IsReadOnly::class); - $attribute = new Attribute($attributeName); - $node->attrGroups = [new AttributeGroup([$attribute])]; - } - - private function addReturnsAttributeToNode(Node\Stmt\ClassMethod $node): void - { - $args = [ - new Node\Arg(new Node\Scalar\String_('string')) - ]; - $attributeName = new FullyQualified(Returns::class); - $attribute = new Attribute($attributeName, $args); - $node->attrGroups = [new AttributeGroup([$attribute])]; - } - - private function addTypeAttributeToNode(Node\Stmt\Property|Node\Stmt\ClassMethod $node): void - { - $args = [ - new Node\Arg(new Node\Scalar\String_('string')) - ]; - $attributeName = new FullyQualified(Type::class); - $attribute = new Attribute($attributeName, $args); - $node->attrGroups = [new AttributeGroup([$attribute])]; - } - - private function addTemplateAttributeToNode(Node\Stmt\Class_ $node, bool $addType = false): void - { - $args = [ - new Node\Arg(new Node\Scalar\String_('T')) - ]; - if ($addType) { - $args[] = new Node\Arg(new Node\Scalar\String_(Exception::class)); - } - $attributeName = new FullyQualified(Template::class); - $attribute = new Attribute($attributeName, $args); - $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); - } - - private function addParamAttributesToNode(Node\Stmt\ClassMethod $node, int $num = 1): void - { - $name = new Identifier('param'); - $value = new Node\Scalar\String_('string'); - $args = []; - for ($i = 0; $i < $num; $i++) { - $args[] = new Node\Arg($value, name: $name); - } - $attributeName = new FullyQualified(Param::class); - $attribute = new Attribute($attributeName, $args); - $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); - } - - private function addParamAttributeToParamNode(Node\Stmt\ClassMethod $node): void - { - $var = new Node\Expr\Variable('param'); - $parameter = new Node\Param($var); - $value = new Node\Scalar\String_('string'); - $args = [new Node\Arg($value)]; - $attributeName = new FullyQualified(Param::class); - $attribute = new Attribute($attributeName, $args); - $parameter->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); - $node->params = [$parameter]; - } - - private function addPropertyAttributesToNode(Node\Stmt\Class_ $node, int $num = 1): void - { - $name = new Identifier('param'); - $value = new Node\Scalar\String_('string'); - $args = []; - for ($i = 0; $i < $num; $i++) { - $args[] = new Node\Arg($value, name: $name); - } - $attributeName = new FullyQualified(Property::class); - $attribute = new Attribute($attributeName, $args); - $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); - } - - private function addPropertyAttributeToPropertyNode(Node\Stmt\Property $node): void - { - $args = [ - new Node\Arg(new Node\Scalar\String_('string')) - ]; - $attributeName = new FullyQualified(Property::class); - $attribute = new Attribute($attributeName, $args); - $node->attrGroups = [new AttributeGroup([$attribute])]; - } - - private function getDocText(Node $node): string - { - $docComment = $node->getDocComment(); - $docText = ''; - if ($docComment instanceof Doc) { - $docText = $docComment->getText(); - } - return $docText; - } } diff --git a/tests/AttributeNodeVisitorTestBase.php b/tests/AttributeNodeVisitorTestBase.php new file mode 100644 index 0000000..74607e8 --- /dev/null +++ b/tests/AttributeNodeVisitorTestBase.php @@ -0,0 +1,50 @@ +nodeVisitor = new AttributeNodeVisitor(); + } + + protected function setDocComment(Node $node, string $text): void + { + $docComment = new Doc( + $text, + ); + $node->setDocComment($docComment); + } + + protected function getDocText(Node $node): string + { + $docComment = $node->getDocComment(); + $docText = ''; + if ($docComment instanceof Doc) { + $docText = $docComment->getText(); + } + return $docText; + } + + protected function addIsReadOnlyAttributeToNode( + Node\Stmt\ClassMethod | Node\Stmt\Property $node + ): void { + $attributeName = new FullyQualified(IsReadOnly::class); + $attribute = new Attribute($attributeName); + $node->attrGroups = [new AttributeGroup([$attribute])]; + } +} diff --git a/tests/IsReadOnlyAttributeNodeVisitorTest.php b/tests/IsReadOnlyAttributeNodeVisitorTest.php new file mode 100644 index 0000000..86e5635 --- /dev/null +++ b/tests/IsReadOnlyAttributeNodeVisitorTest.php @@ -0,0 +1,40 @@ +addIsReadOnlyAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @readonly\n */", $docText); + } + + public function testAddsReadOnlyPHPDocMaintainingExistingPHPDoc(): void + { + $node = new Node\Stmt\Property(0, []); + $this->setDocComment($node, self::UNTOUCHED); + $this->addIsReadOnlyAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * untouched\n * @readonly\n */", $docText); + } +} diff --git a/tests/ParamAttributeNodeVisitorTest.php b/tests/ParamAttributeNodeVisitorTest.php new file mode 100644 index 0000000..56a4432 --- /dev/null +++ b/tests/ParamAttributeNodeVisitorTest.php @@ -0,0 +1,75 @@ +addParamAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @param string \$param\n */", $docText); + } + + public function testAddsSeveralParamPHPDocs(): void + { + $node = new Node\Stmt\ClassMethod('Test'); + $this->addParamAttributesToNode($node, 2); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @param string \$param\n * @param string \$param\n */", $docText); + } + + public function testAddsMultipleParamPHPDocs(): void + { + $node = new Node\Stmt\ClassMethod('Test'); + $this->addParamAttributesToNode($node); + $this->addParamAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @param string \$param\n * @param string \$param\n */", $docText); + } + + public function testAddsParamPHPDocToParam(): void + { + $node = new Node\Stmt\ClassMethod('Test'); + $this->addParamAttributeToParamNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @param string \$param\n */", $docText); + } + + private function addParamAttributesToNode(Node\Stmt\ClassMethod $node, int $num = 1): void + { + $name = new Identifier('param'); + $value = new Node\Scalar\String_('string'); + $args = []; + for ($i = 0; $i < $num; $i++) { + $args[] = new Node\Arg($value, name: $name); + } + $attributeName = new FullyQualified(Param::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); + } + + private function addParamAttributeToParamNode(Node\Stmt\ClassMethod $node): void + { + $var = new Node\Expr\Variable('param'); + $parameter = new Node\Param($var); + $value = new Node\Scalar\String_('string'); + $args = [new Node\Arg($value)]; + $attributeName = new FullyQualified(Param::class); + $attribute = new Attribute($attributeName, $args); + $parameter->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); + $node->params = [$parameter]; + } +} diff --git a/tests/PropertyAttributeNodeVisitorTest.php b/tests/PropertyAttributeNodeVisitorTest.php new file mode 100644 index 0000000..c7de619 --- /dev/null +++ b/tests/PropertyAttributeNodeVisitorTest.php @@ -0,0 +1,73 @@ +addPropertyAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property string \$param\n */", $docText); + } + + public function testAddsSeveralPropertyPHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addPropertyAttributesToNode($node, 2); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property string \$param\n * @property string \$param\n */", $docText); + } + + public function testAddsMultiplePropertyPHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addPropertyAttributesToNode($node); + $this->addPropertyAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property string \$param\n * @property string \$param\n */", $docText); + } + + public function testAddsVarPHPDocForPropertyAttribute(): void + { + $node = new Node\Stmt\Property(0, []); + $this->addPropertyAttributeToPropertyNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @var string\n */", $docText); + } + + private function addPropertyAttributesToNode(Node\Stmt\Class_ $node, int $num = 1): void + { + $name = new Identifier('param'); + $value = new Node\Scalar\String_('string'); + $args = []; + for ($i = 0; $i < $num; $i++) { + $args[] = new Node\Arg($value, name: $name); + } + $attributeName = new FullyQualified(Property::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); + } + + private function addPropertyAttributeToPropertyNode(Node\Stmt\Property $node): void + { + $args = [ + new Node\Arg(new Node\Scalar\String_('string')) + ]; + $attributeName = new FullyQualified(Property::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = [new AttributeGroup([$attribute])]; + } +} diff --git a/tests/PropertyReadAttributeNodeVisitorTest.php b/tests/PropertyReadAttributeNodeVisitorTest.php new file mode 100644 index 0000000..42d5404 --- /dev/null +++ b/tests/PropertyReadAttributeNodeVisitorTest.php @@ -0,0 +1,54 @@ +addPropertyReadAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property-read string \$param\n */", $docText); + } + + public function testAddsSeveralPropertyReadPHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addPropertyReadAttributesToNode($node, 2); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property-read string \$param\n * @property-read string \$param\n */", $docText); + } + + public function testAddsMultiplePropertyReadPHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addPropertyReadAttributesToNode($node); + $this->addPropertyReadAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property-read string \$param\n * @property-read string \$param\n */", $docText); + } + + private function addPropertyReadAttributesToNode(Node\Stmt\Class_ $node, int $num = 1): void + { + $name = new Identifier('param'); + $value = new Node\Scalar\String_('string'); + $args = []; + for ($i = 0; $i < $num; $i++) { + $args[] = new Node\Arg($value, name: $name); + } + $attributeName = new FullyQualified(PropertyRead::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); + } +} diff --git a/tests/PropertyWriteAttributeNodeVisitorTest.php b/tests/PropertyWriteAttributeNodeVisitorTest.php new file mode 100644 index 0000000..263082a --- /dev/null +++ b/tests/PropertyWriteAttributeNodeVisitorTest.php @@ -0,0 +1,54 @@ +addPropertyWriteAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property-write string \$param\n */", $docText); + } + + public function testAddsSeveralPropertyWritePHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addPropertyWriteAttributesToNode($node, 2); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property-write string \$param\n * @property-write string \$param\n */", $docText); + } + + public function testAddsMultiplePropertyWritePHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addPropertyWriteAttributesToNode($node); + $this->addPropertyWriteAttributesToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @property-write string \$param\n * @property-write string \$param\n */", $docText); + } + + private function addPropertyWriteAttributesToNode(Node\Stmt\Class_ $node, int $num = 1): void + { + $name = new Identifier('param'); + $value = new Node\Scalar\String_('string'); + $args = []; + for ($i = 0; $i < $num; $i++) { + $args[] = new Node\Arg($value, name: $name); + } + $attributeName = new FullyQualified(PropertyWrite::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); + } +} diff --git a/tests/ReturnsAttributeNodeVisitorTest.php b/tests/ReturnsAttributeNodeVisitorTest.php new file mode 100644 index 0000000..8e59147 --- /dev/null +++ b/tests/ReturnsAttributeNodeVisitorTest.php @@ -0,0 +1,31 @@ +addReturnsAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @return string\n */", $docText); + } + + private function addReturnsAttributeToNode(Node\Stmt\ClassMethod $node): void + { + $args = [ + new Node\Arg(new Node\Scalar\String_('string')) + ]; + $attributeName = new FullyQualified(Returns::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = [new AttributeGroup([$attribute])]; + } +} diff --git a/tests/TemplateAttributeNodeVisitorTest.php b/tests/TemplateAttributeNodeVisitorTest.php new file mode 100644 index 0000000..caa7585 --- /dev/null +++ b/tests/TemplateAttributeNodeVisitorTest.php @@ -0,0 +1,54 @@ +addTemplateAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @template T\n */", $docText); + } + + public function testAddsTemplateWithTypePHPDoc(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addTemplateAttributeToNode($node, true); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @template T of Exception\n */", $docText); + } + + public function testAddsMultipleTemplatePHPDocs(): void + { + $node = new Node\Stmt\Class_('Test'); + $this->addTemplateAttributeToNode($node); + $this->addTemplateAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @template T\n * @template T\n */", $docText); + } + + private function addTemplateAttributeToNode(Node\Stmt\Class_ $node, bool $addType = false): void + { + $args = [ + new Node\Arg(new Node\Scalar\String_('T')) + ]; + if ($addType) { + $args[] = new Node\Arg(new Node\Scalar\String_(Exception::class)); + } + $attributeName = new FullyQualified(Template::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = array_merge($node->attrGroups, [new AttributeGroup([$attribute])]); + } +} diff --git a/tests/TypeAttributeNodeVisitorTest.php b/tests/TypeAttributeNodeVisitorTest.php new file mode 100644 index 0000000..ffd0262 --- /dev/null +++ b/tests/TypeAttributeNodeVisitorTest.php @@ -0,0 +1,40 @@ +addTypeAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @var string\n */", $docText); + } + + public function testAddsReturnPHPDocWithTypeAttribute(): void + { + $node = new Node\Stmt\ClassMethod('Test'); + $this->addTypeAttributeToNode($node); + $this->nodeVisitor->enterNode($node); + $docText = $this->getDocText($node); + $this->assertEquals("/**\n * @return string\n */", $docText); + } + + private function addTypeAttributeToNode(Node\Stmt\Property|Node\Stmt\ClassMethod $node): void + { + $args = [ + new Node\Arg(new Node\Scalar\String_('string')) + ]; + $attributeName = new FullyQualified(Type::class); + $attribute = new Attribute($attributeName, $args); + $node->attrGroups = [new AttributeGroup([$attribute])]; + } +}