diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index d0c1fb55..12b371ca 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: steps: - name: "Dependabot metadata" id: "metadata" - uses: "dependabot/fetch-metadata@v2.4.0" + uses: "dependabot/fetch-metadata@v2.5.0" with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: "Enable auto-merge for Dependabot PRs" diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 19975936..32ac9bbd 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -19,7 +19,7 @@ jobs: - name: "Deploy" if: "${{ github.event_name == 'push' && github.ref == 'refs/heads/6.x' }}" - uses: "actions/upload-artifact@v5" + uses: "actions/upload-artifact@v7" with: name: "documentation" path: "build/docs" diff --git a/composer.lock b/composer.lock index 5e78026d..eff0f0d0 100644 --- a/composer.lock +++ b/composer.lock @@ -8,29 +8,29 @@ "packages": [ { "name": "doctrine/deprecations", - "version": "1.1.5", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" + "phpunit/phpunit": "<=7.5 || >=14" }, "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", "psr/log": "^1 || ^2 || ^3" }, "suggest": { @@ -50,22 +50,22 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2026-02-07T07:09:04+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.2", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -108,9 +108,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-10-21T19:32:17+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -167,16 +167,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.4", + "version": "5.6.6", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2" + "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90a04bcbf03784066f16038e87e23a0a83cee3c2", - "reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/5cee1d3dfc2d2aa6599834520911d246f656bcb8", + "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8", "shasum": "" }, "require": { @@ -186,7 +186,7 @@ "phpdocumentor/reflection-common": "^2.2", "phpdocumentor/type-resolver": "^1.7", "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1" + "webmozart/assert": "^1.9.1 || ^2" }, "require-dev": { "mockery/mockery": "~1.3.5 || ~1.6.0", @@ -225,9 +225,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.4" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.6" }, - "time": "2025-11-17T21:13:10+00:00" + "time": "2025-12-22T21:13:58+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -289,16 +289,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.0", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { @@ -330,9 +330,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" }, - "time": "2025-08-30T15:50:23+00:00" + "time": "2026-01-25T14:56:51+00:00" }, { "name": "symfony/polyfill-php80", @@ -1190,22 +1190,22 @@ }, { "name": "phpspec/prophecy-phpunit", - "version": "v2.4.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy-phpunit.git", - "reference": "d3c28041d9390c9bca325a08c5b2993ac855bded" + "reference": "89f91b01d0640b7820e427e02a007bc6489d8a26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/d3c28041d9390c9bca325a08c5b2993ac855bded", - "reference": "d3c28041d9390c9bca325a08c5b2993ac855bded", + "url": "https://api.github.com/repos/phpspec/prophecy-phpunit/zipball/89f91b01d0640b7820e427e02a007bc6489d8a26", + "reference": "89f91b01d0640b7820e427e02a007bc6489d8a26", "shasum": "" }, "require": { "php": "^7.3 || ^8", "phpspec/prophecy": "^1.18", - "phpunit/phpunit": "^9.1 || ^10.1 || ^11.0 || ^12.0" + "phpunit/phpunit": "^9.1 || ^10.1 || ^11.0 || ^12.0 || ^13.0" }, "require-dev": { "phpstan/phpstan": "^1.10" @@ -1239,9 +1239,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy-phpunit/issues", - "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.4.0" + "source": "https://github.com/phpspec/prophecy-phpunit/tree/v2.5.0" }, - "time": "2025-05-13T13:52:32+00:00" + "time": "2026-02-09T15:40:55+00:00" }, { "name": "phpstan/extension-installer", @@ -1723,16 +1723,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.58", + "version": "10.5.63", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca" + "reference": "33198268dad71e926626b618f3ec3966661e4d90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e24fb46da450d8e6a5788670513c1af1424f16ca", - "reference": "e24fb46da450d8e6a5788670513c1af1424f16ca", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/33198268dad71e926626b618f3ec3966661e4d90", + "reference": "33198268dad71e926626b618f3ec3966661e4d90", "shasum": "" }, "require": { @@ -1753,7 +1753,7 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.4", + "sebastian/comparator": "^5.0.5", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.4", @@ -1804,7 +1804,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.58" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.63" }, "funding": [ { @@ -1828,7 +1828,7 @@ "type": "tidelift" } ], - "time": "2025-09-28T12:04:46+00:00" + "time": "2026-01-27T05:48:37+00:00" }, { "name": "psalm/phar", @@ -2094,16 +2094,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.4", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e" + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e", - "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55dfef806eb7dfeb6e7a6935601fef866f8ca48d", + "reference": "55dfef806eb7dfeb6e7a6935601fef866f8ca48d", "shasum": "" }, "require": { @@ -2159,7 +2159,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.5" }, "funding": [ { @@ -2179,7 +2179,7 @@ "type": "tidelift" } ], - "time": "2025-09-07T05:25:07+00:00" + "time": "2026-01-24T09:25:16+00:00" }, { "name": "sebastian/complexity", @@ -3023,16 +3023,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", - "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -3061,7 +3061,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.3.0" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -3069,7 +3069,7 @@ "type": "github" } ], - "time": "2025-11-13T13:44:09+00:00" + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9dd1e5bf..4a60c177 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -225,8 +225,5 @@ - - aliasesToFullyQualifiedNames($namespace)]]> - diff --git a/src/phpDocumentor/Reflection/Php/Constant.php b/src/phpDocumentor/Reflection/Php/Constant.php index 1b334758..736dcdd0 100644 --- a/src/phpDocumentor/Reflection/Php/Constant.php +++ b/src/phpDocumentor/Reflection/Php/Constant.php @@ -19,6 +19,7 @@ use phpDocumentor\Reflection\Fqsen; use phpDocumentor\Reflection\Location; use phpDocumentor\Reflection\Metadata\MetaDataContainer as MetaDataContainerInterface; +use phpDocumentor\Reflection\Type; use function is_string; use function trigger_error; @@ -52,6 +53,7 @@ public function __construct( Location|null $endLocation = null, Visibility|null $visibility = null, private readonly bool $final = false, + private readonly Type|null $type = null, ) { $this->location = $location ?: new Location(-1); $this->endLocation = $endLocation ?: new Location(-1); @@ -135,4 +137,9 @@ public function isFinal(): bool { return $this->final; } + + public function getType(): Type|null + { + return $this->type; + } } diff --git a/src/phpDocumentor/Reflection/Php/Expression/ExpressionPrinter.php b/src/phpDocumentor/Reflection/Php/Expression/ExpressionPrinter.php index 5fe66ae7..5e9162ec 100644 --- a/src/phpDocumentor/Reflection/Php/Expression/ExpressionPrinter.php +++ b/src/phpDocumentor/Reflection/Php/Expression/ExpressionPrinter.php @@ -86,7 +86,10 @@ protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node): string { $renderedName = parent::pObjectProperty($node->name); - if ($node->class instanceof Name) { + if ($node->class instanceof Name\FullyQualified) { + $className = parent::pName_FullyQualified($node->class); + $className = $this->typeResolver->resolve($className, $this->context); + } elseif ($node->class instanceof Name) { $className = parent::pName($node->class); $className = $this->typeResolver->resolve($className, $this->context); } else { diff --git a/src/phpDocumentor/Reflection/Php/Factory/ClassConstant.php b/src/phpDocumentor/Reflection/Php/Factory/ClassConstant.php index 7d6ed2b9..e49bd2be 100644 --- a/src/phpDocumentor/Reflection/Php/Factory/ClassConstant.php +++ b/src/phpDocumentor/Reflection/Php/Factory/ClassConstant.php @@ -93,6 +93,7 @@ protected function doCreate( new Location($const->getEndLine()), $this->buildVisibility($const), $const->isFinal(), + (new Type())->fromPhpParser($const->getType(), $context->getTypeContext()), ); foreach ($this->reducers as $reducer) { diff --git a/src/phpDocumentor/Reflection/Php/Factory/ClassConstantIterator.php b/src/phpDocumentor/Reflection/Php/Factory/ClassConstantIterator.php index 93e1f23c..278d21ae 100644 --- a/src/phpDocumentor/Reflection/Php/Factory/ClassConstantIterator.php +++ b/src/phpDocumentor/Reflection/Php/Factory/ClassConstantIterator.php @@ -17,7 +17,10 @@ use Override; use phpDocumentor\Reflection\Fqsen; use PhpParser\Comment\Doc; +use PhpParser\Node\ComplexType; use PhpParser\Node\Expr; +use PhpParser\Node\Identifier; +use PhpParser\Node\Name; use PhpParser\Node\Stmt\ClassConst; /** @@ -123,6 +126,14 @@ public function isFinal(): bool return $this->classConstants->isFinal(); } + /** + * Gets the type of the constant. + */ + public function getType(): Identifier|Name|ComplexType|null + { + return $this->classConstants->type; + } + /** @link http://php.net/manual/en/iterator.current.php */ #[Override] public function current(): self diff --git a/src/phpDocumentor/Reflection/Php/Factory/File.php b/src/phpDocumentor/Reflection/Php/Factory/File.php index 46fba96d..22b95e7b 100644 --- a/src/phpDocumentor/Reflection/Php/Factory/File.php +++ b/src/phpDocumentor/Reflection/Php/Factory/File.php @@ -24,6 +24,7 @@ use phpDocumentor\Reflection\Php\NodesFactory; use phpDocumentor\Reflection\Php\StrategyContainer; use phpDocumentor\Reflection\Types\Context; +use phpDocumentor\Reflection\Types\FileToContext; use PhpParser\Comment\Doc; use PhpParser\Node; use PhpParser\Node\Stmt\Class_ as ClassNode; @@ -106,7 +107,9 @@ private function createFile(CreateCommand $command): FileElement $code = $file->getContents(); $nodes = $this->nodesFactory->create($code); - $docBlock = $this->createFileDocBlock(null, $nodes); + $fileToContext = new FileToContext(); + $typeContext = $fileToContext($nodes); + $docBlock = $this->createFileDocBlock($typeContext, $nodes); $result = new FileElement( $file->md5(), @@ -115,7 +118,7 @@ private function createFile(CreateCommand $command): FileElement $docBlock, ); - $this->createElements($command->getContext()->push($result), $nodes, $command->getStrategies()); + $this->createElements($command->getContext()->push($result)->withTypeContext($typeContext), $nodes, $command->getStrategies()); return $result; } diff --git a/src/phpDocumentor/Reflection/Types/BaseToContext.php b/src/phpDocumentor/Reflection/Types/BaseToContext.php new file mode 100644 index 00000000..26b5acbe --- /dev/null +++ b/src/phpDocumentor/Reflection/Types/BaseToContext.php @@ -0,0 +1,59 @@ + + */ + protected static function flattenUsage(array $usages): array + { + return array_merge([], ...array_merge([], ...array_map( + static fn ($use): array => array_map( + static function (Node\UseItem|UseUse $useUse) use ($use): array { + if ($use instanceof GroupUse) { + return [ + (string) $useUse->getAlias() => $use->prefix->toString() . '\\' . $useUse->name->toString(), + ]; + } + + return [(string) $useUse->getAlias() => $useUse->name->toString()]; + }, + $use->uses, + ), + $usages, + ))); + } + + /** + * @param Node[] $nodes + * + * @return Use_[]|GroupUse[] + */ + protected static function filterUsage(array $nodes): array + { + return array_filter( + $nodes, + static fn (Node $node): bool => ( + $node instanceof Use_ + || $node instanceof GroupUse + ) && in_array($node->type, [Use_::TYPE_UNKNOWN, Use_::TYPE_NORMAL], true), + ); + } +} diff --git a/src/phpDocumentor/Reflection/Types/FileToContext.php b/src/phpDocumentor/Reflection/Types/FileToContext.php new file mode 100644 index 00000000..7a45e7e8 --- /dev/null +++ b/src/phpDocumentor/Reflection/Types/FileToContext.php @@ -0,0 +1,19 @@ +name ? $namespace->name->toString() : '', - $this->aliasesToFullyQualifiedNames($namespace), - ); - } - - /** @return string[] indexed by alias */ - private function aliasesToFullyQualifiedNames(Namespace_ $namespace): array - { - // flatten(flatten(map(stuff))) - return array_merge([], ...array_merge([], ...array_map( - static fn ($use): array => array_map( - static function (Node\UseItem|UseUse $useUse) use ($use): array { - if ($use instanceof GroupUse) { - return [ - (string) $useUse->getAlias() => $use->prefix->toString() . '\\' . $useUse->name->toString(), - ]; - } - - return [(string) $useUse->getAlias() => $useUse->name->toString()]; - }, - $use->uses, - ), - $this->classAlikeUses($namespace), - ))); - } - - /** @return Use_[]|GroupUse[] */ - private function classAlikeUses(Namespace_ $namespace): array - { - return array_filter( - $namespace->stmts, - static fn (Node $node): bool => ( - $node instanceof Use_ - || $node instanceof GroupUse - ) && in_array($node->type, [Use_::TYPE_UNKNOWN, Use_::TYPE_NORMAL], true), + self::flattenUsage(self::filterUsage($namespace->stmts)), ); } } diff --git a/tests/integration/EnumTest.php b/tests/integration/EnumTest.php index 03e2c30f..bf3d12e6 100644 --- a/tests/integration/EnumTest.php +++ b/tests/integration/EnumTest.php @@ -115,10 +115,9 @@ public function testEnumSupportInMethod(): void $method->getArguments()[0]->getType() ); - //This should be fixed in #219 -// self::assertEquals( -// '\MyNamespace\MyEnum::VALUE1', -// $method->getArguments()[0]->getDefault() -// ); + self::assertEquals( + '\MyNamespace\MyEnum::VALUE1', + $method->getArguments()[0]->getDefault() + ); } } diff --git a/tests/integration/ProjectCreationTest.php b/tests/integration/ProjectCreationTest.php index 7cd1701a..63558a71 100644 --- a/tests/integration/ProjectCreationTest.php +++ b/tests/integration/ProjectCreationTest.php @@ -17,6 +17,7 @@ use phpDocumentor\Reflection\DocBlock\Tags\Param; use phpDocumentor\Reflection\File\LocalFile; use phpDocumentor\Reflection\Php\Class_; +use phpDocumentor\Reflection\Php\Expression; use phpDocumentor\Reflection\Php\Function_; use phpDocumentor\Reflection\Php\ProjectFactory; use phpDocumentor\Reflection\Types\Integer; @@ -250,4 +251,36 @@ public function testMethodReturnType() : void $this->assertEquals(new String_(), $interface->getMethods()['\Packing::getName()']->getReturnType()); } + + public function testFunctionContantDefaultIsResolved() : void + { + $fileName = __DIR__ . '/data/GlobalFiles/function_constant_default.php'; + $project = $this->fixture->create( + 'MyProject', + [new LocalFile($fileName)] + ); + + $this->assertArrayHasKey($fileName, $project->getFiles()); + $functions = $project->getFiles()[$fileName]->getFunctions(); + + self::assertEquals( + new Expression( + '{{ PHPDOCa2f2ed4f8ebc2cbb4c21a29dc40ab61d }}', + [ + '{{ PHPDOCa2f2ed4f8ebc2cbb4c21a29dc40ab61d }}' => new Fqsen('\Acme\Plugin::class'), + ], + ), + $functions['\foo()']->getArguments()[0]->getDefault(false) + ); + + self::assertEquals( + new Expression( + '{{ PHPDOCa8cfde6331bd59eb2ac96f8911c4b666 }}', + [ + '{{ PHPDOCa8cfde6331bd59eb2ac96f8911c4b666 }}' => new Object_(), + ], + ), + $functions['\bar()']->getArguments()[0]->getDefault(false) + ); + } } diff --git a/tests/integration/TypedConstantTest.php b/tests/integration/TypedConstantTest.php new file mode 100644 index 00000000..f4575749 --- /dev/null +++ b/tests/integration/TypedConstantTest.php @@ -0,0 +1,34 @@ +create('My project', [new LocalFile($file)]); + + $class = $project->getFiles()[$file]->getClasses()['\PHP83\TypedConstants']; + $constants = $class->getConstants(); + + $this->assertEquals(new String_(), $constants['\PHP83\TypedConstants::NAME']->getType()); + $this->assertEquals(new Integer(), $constants['\PHP83\TypedConstants::COUNT']->getType()); + $this->assertEquals(new Compound([new String_(), new Integer()]), $constants['\PHP83\TypedConstants::UNION']->getType()); + $this->assertEquals(new Nullable(new String_()), $constants['\PHP83\TypedConstants::NULLABLE']->getType()); + $this->assertNull($constants['\PHP83\TypedConstants::UNTYPED']->getType()); + } +} diff --git a/tests/integration/data/GlobalFiles/function_constant_default.php b/tests/integration/data/GlobalFiles/function_constant_default.php new file mode 100644 index 00000000..685a0d03 --- /dev/null +++ b/tests/integration/data/GlobalFiles/function_constant_default.php @@ -0,0 +1,7 @@ +fixture->getVisibility()); } + public function testGetTypeReturnsNullByDefault(): void + { + self::assertNull($this->fixture->getType()); + } + + public function testGetTypeReturnsTypeWhenProvided(): void + { + $type = new String_(); + $fixture = new Constant( + $this->fqsen, + $this->docBlock, + new Expression($this->value), + null, + null, + null, + false, + $type, + ); + + self::assertSame($type, $fixture->getType()); + } + public function testLineAndColumnNumberIsReturnedWhenALocationIsProvided(): void { $fixture = new Constant($this->fqsen, $this->docBlock, null, new Location(100, 20), new Location(101, 20)); diff --git a/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantIteratorTest.php b/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantIteratorTest.php index 61f5cf7c..e83c4d7f 100644 --- a/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantIteratorTest.php +++ b/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantIteratorTest.php @@ -19,6 +19,8 @@ use PhpParser\Comment\Doc; use PhpParser\Node\Const_; use PhpParser\Node\Expr\Variable; +use PhpParser\Node\Identifier; +use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\ClassConst; use PHPUnit\Framework\Attributes\CoversClass; @@ -78,6 +80,31 @@ public function testGetDocCommentPropFirst(): void $this->assertEquals('test', $fixture->getDocComment()->getText()); } + public function testGetTypeReturnsNullWhenUntyped(): void + { + $const = new Const_('\Space\MyClass::MY_CONST1', new String_('a')); + $const->setAttribute('fqsen', new Fqsen((string) $const->name)); + + $classConstantNode = new ClassConst([$const]); + + $fixture = new ClassConstantIterator($classConstantNode); + + $this->assertNull($fixture->getType()); + } + + public function testGetTypeReturnsTypeWhenTyped(): void + { + $const = new Const_('\Space\MyClass::MY_CONST1', new String_('a')); + $const->setAttribute('fqsen', new Fqsen((string) $const->name)); + + $classConstantNode = new ClassConst([$const], 0, [], [], new Identifier('string')); + + $fixture = new ClassConstantIterator($classConstantNode); + + $this->assertInstanceOf(Identifier::class, $fixture->getType()); + $this->assertEquals('string', $fixture->getType()->toString()); + } + public function testGetDocComment(): void { $const = m::mock(Const_::class); diff --git a/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantTest.php b/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantTest.php index dec052dc..b0388675 100644 --- a/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantTest.php +++ b/tests/unit/phpDocumentor/Reflection/Php/Factory/ClassConstantTest.php @@ -24,8 +24,10 @@ use phpDocumentor\Reflection\Php\ProjectFactoryStrategies; use phpDocumentor\Reflection\Php\Trait_ as TraitElement; use phpDocumentor\Reflection\Types\Null_; +use phpDocumentor\Reflection\Types\String_ as StringType; use PhpParser\Comment\Doc; use PhpParser\Node\Const_; +use PhpParser\Node\Identifier; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\Class_ as ClassNode; use PhpParser\Node\Stmt\ClassConst; @@ -138,6 +140,29 @@ public function testCreateForEnum(): void self::assertInstanceOf(ConstantDescriptor::class, current($result->getConstants())); } + public function testCreateWithTypedConstant(): void + { + $const = new Const_('\Space\MyClass::MY_CONST1', new String_('a')); + $const->setAttribute('fqsen', new Fqsen((string) $const->name)); + $constantStub = new ClassConst([$const], ClassNode::MODIFIER_PUBLIC, [], [], new Identifier('string')); + + $class = $this->performCreate($constantStub); + + $constant = current($class->getConstants()); + $this->assertInstanceOf(ConstantDescriptor::class, $constant); + $this->assertEquals(new StringType(), $constant->getType()); + } + + public function testCreateWithUntypedConstantHasNullType(): void + { + $constantStub = $this->buildConstantIteratorStub(); + + $class = $this->performCreate($constantStub); + + $constant = current($class->getConstants()); + $this->assertNull($constant->getType()); + } + public function testCreateWithDocBlock(): void { $doc = new Doc('text'); diff --git a/tests/unit/phpDocumentor/Reflection/Php/Factory/FileTest.php b/tests/unit/phpDocumentor/Reflection/Php/Factory/FileTest.php index 7e7fdd94..aa0299bb 100644 --- a/tests/unit/phpDocumentor/Reflection/Php/Factory/FileTest.php +++ b/tests/unit/phpDocumentor/Reflection/Php/Factory/FileTest.php @@ -106,7 +106,7 @@ public function testMiddlewareIsChecked(): void public function testFileGetsCommentFromFirstNode(Node $node, DocBlockDescriptor $docblock): void { $this->nodesFactoryMock->create(file_get_contents(__FILE__))->willReturn([$node]); - $this->docBlockFactory->create('Text', null)->willReturn($docblock); + $this->docBlockFactory->create('Text', Argument::any())->willReturn($docblock); $strategies = $this->prophesize(StrategyContainer::class); $strategies->findMatching(Argument::type(ContextStack::class), $node)->willReturn(