From 98681d3b5503ca3089e9d06b2b2b3643ca211f9d Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 01:49:13 +0200 Subject: [PATCH 01/15] cs --- src/PhpGenerator/Factory.php | 18 +++++++++--------- src/PhpGenerator/Printer.php | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 979ca1c7..3d6706c4 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -70,7 +70,7 @@ public function fromClassReflection( } $class->setComment(Helpers::unformatDocComment((string) $from->getDocComment())); - $class->setAttributes(self::getAttributes($from)); + $class->setAttributes($this->getAttributes($from)); if ($from->getParentClass()) { $class->setExtends($from->getParentClass()->name); $class->setImplements(array_diff($class->getImplements(), $from->getParentClass()->getInterfaceNames())); @@ -160,7 +160,7 @@ public function fromMethodReflection(\ReflectionMethod $from): Method $method->setReturnReference($from->returnsReference()); $method->setVariadic($from->isVariadic()); $method->setComment(Helpers::unformatDocComment((string) $from->getDocComment())); - $method->setAttributes(self::getAttributes($from)); + $method->setAttributes($this->getAttributes($from)); $method->setReturnType((string) $from->getReturnType()); return $method; @@ -177,7 +177,7 @@ public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody $function->setComment(Helpers::unformatDocComment((string) $from->getDocComment())); } - $function->setAttributes(self::getAttributes($from)); + $function->setAttributes($this->getAttributes($from)); $function->setReturnType((string) $from->getReturnType()); if ($withBody) { @@ -196,8 +196,8 @@ public function fromCallable(callable $from): Method|GlobalFunction|Closure { $ref = Nette\Utils\Callback::toReflection($from); return $ref instanceof \ReflectionMethod - ? self::fromMethodReflection($ref) - : self::fromFunctionReflection($ref); + ? $this->fromMethodReflection($ref) + : $this->fromFunctionReflection($ref); } @@ -226,7 +226,7 @@ public function fromParameterReflection(\ReflectionParameter $from): Parameter $param->setNullable($param->isNullable() && $param->getDefaultValue() !== null); } - $param->setAttributes(self::getAttributes($from)); + $param->setAttributes($this->getAttributes($from)); return $param; } @@ -238,7 +238,7 @@ public function fromConstantReflection(\ReflectionClassConstant $from): Constant $const->setVisibility($this->getVisibility($from)); $const->setFinal(PHP_VERSION_ID >= 80100 ? $from->isFinal() : false); $const->setComment(Helpers::unformatDocComment((string) $from->getDocComment())); - $const->setAttributes(self::getAttributes($from)); + $const->setAttributes($this->getAttributes($from)); return $const; } @@ -248,7 +248,7 @@ public function fromCaseReflection(\ReflectionClassConstant $from): EnumCase $const = new EnumCase($from->name); $const->setValue($from->getValue()->value ?? null); $const->setComment(Helpers::unformatDocComment((string) $from->getDocComment())); - $const->setAttributes(self::getAttributes($from)); + $const->setAttributes($this->getAttributes($from)); return $const; } @@ -265,7 +265,7 @@ public function fromPropertyReflection(\ReflectionProperty $from): Property $prop->setInitialized($from->hasType() && array_key_exists($prop->getName(), $defaults)); $prop->setReadOnly(PHP_VERSION_ID >= 80100 ? $from->isReadOnly() : false); $prop->setComment(Helpers::unformatDocComment((string) $from->getDocComment())); - $prop->setAttributes(self::getAttributes($from)); + $prop->setAttributes($this->getAttributes($from)); return $prop; } diff --git a/src/PhpGenerator/Printer.php b/src/PhpGenerator/Printer.php index 48128454..57718375 100644 --- a/src/PhpGenerator/Printer.php +++ b/src/PhpGenerator/Printer.php @@ -49,7 +49,7 @@ public function printFunction(GlobalFunction $function, ?PhpNamespace $namespace $body = ltrim(rtrim(Strings::normalize($body)) . "\n"); return $this->printDocComment($function) - . self::printAttributes($function->getAttributes()) + . $this->printAttributes($function->getAttributes()) . $line . $this->printParameters($function, strlen($line) + strlen($returnType) + 2) // 2 = parentheses . $returnType @@ -72,7 +72,7 @@ public function printClosure(Closure $closure, ?PhpNamespace $namespace = null): $body = Helpers::simplifyTaggedNames($closure->getBody(), $this->namespace); $body = ltrim(rtrim(Strings::normalize($body)) . "\n"); - return self::printAttributes($closure->getAttributes(), inline: true) + return $this->printAttributes($closure->getAttributes(), inline: true) . 'function ' . ($closure->getReturnReference() ? '&' : '') . $this->printParameters($closure) @@ -93,7 +93,7 @@ public function printArrowFunction(Closure $closure, ?PhpNamespace $namespace = $body = Helpers::simplifyTaggedNames($closure->getBody(), $this->namespace); - return self::printAttributes($closure->getAttributes()) + return $this->printAttributes($closure->getAttributes()) . 'fn' . ($closure->getReturnReference() ? '&' : '') . $this->printParameters($closure) @@ -120,7 +120,7 @@ public function printMethod(Method $method, ?PhpNamespace $namespace = null, boo $braceOnNextLine = $this->bracesOnNextLine && !str_contains($params, "\n"); return $this->printDocComment($method) - . self::printAttributes($method->getAttributes()) + . $this->printAttributes($method->getAttributes()) . $line . $params . $returnType @@ -159,7 +159,7 @@ public function printClass( foreach ($class->getCases() as $case) { $enumType ??= is_scalar($case->getValue()) ? get_debug_type($case->getValue()) : null; $cases[] = $this->printDocComment($case) - . self::printAttributes($case->getAttributes()) + . $this->printAttributes($case->getAttributes()) . 'case ' . $case->getName() . ($case->getValue() === null ? '' : ' = ' . $this->dump($case->getValue())) . ";\n"; @@ -174,7 +174,7 @@ public function printClass( . 'const ' . $const->getName() . ' = '; $consts[] = $this->printDocComment($const) - . self::printAttributes($const->getAttributes()) + . $this->printAttributes($const->getAttributes()) . $def . $this->dump($const->getValue(), strlen($def)) . ";\n"; } @@ -205,7 +205,7 @@ public function printClass( . '$' . $property->getName()); $properties[] = $this->printDocComment($property) - . self::printAttributes($property->getAttributes()) + . $this->printAttributes($property->getAttributes()) . $def . ($property->getValue() === null && !$property->isInitialized() ? '' @@ -243,7 +243,7 @@ public function printClass( $line[] = $class->getName() ? null : '{'; return $this->printDocComment($class) - . self::printAttributes($class->getAttributes()) + . $this->printAttributes($class->getAttributes()) . implode(' ', array_filter($line)) . ($class->getName() ? "\n{\n" : "\n") . ($members ? $this->indent(implode("\n", $members)) : '') @@ -333,7 +333,7 @@ protected function printParameters(Closure|GlobalFunction|Method $function, int $promoted = $param instanceof PromotedParameter ? $param : null; $params[] = ($promoted ? $this->printDocComment($promoted) : '') - . ($attrs = self::printAttributes($param->getAttributes(), inline: true)) + . ($attrs = $this->printAttributes($param->getAttributes(), inline: true)) . ($promoted ? ($promoted->getVisibility() ?: 'public') . ($promoted->isReadOnly() && $type ? ' readonly' : '') From 018ce438d29d2f63d111af0b2da0ccb25db3867d Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 13:38:14 +0200 Subject: [PATCH 02/15] tests: refactoring --- tests/PhpGenerator/Extractor.extractAll.phpt | 52 +------------------- tests/PhpGenerator/expected/Extractor.expect | 22 +++++++++ tests/PhpGenerator/fixtures/extractor.php | 21 ++++++++ 3 files changed, 45 insertions(+), 50 deletions(-) create mode 100644 tests/PhpGenerator/expected/Extractor.expect create mode 100644 tests/PhpGenerator/fixtures/extractor.php diff --git a/tests/PhpGenerator/Extractor.extractAll.phpt b/tests/PhpGenerator/Extractor.extractAll.phpt index 3eccfdd8..fd704ca2 100644 --- a/tests/PhpGenerator/Extractor.extractAll.phpt +++ b/tests/PhpGenerator/Extractor.extractAll.phpt @@ -24,56 +24,8 @@ sameFile(__DIR__ . '/expected/Extractor.traits.expect', (string) $file); $file = (new Extractor(file_get_contents(__DIR__ . '/fixtures/bodies.php')))->extractAll(); sameFile(__DIR__ . '/expected/Extractor.bodies.expect', (string) $file); -$file = (new Extractor(<<<'XX' - extractAll(); -Assert::type(Nette\PhpGenerator\PhpFile::class, $file); -Assert::match(<<<'XX' - extractAll(); +sameFile(__DIR__ . '/expected/Extractor.expect', (string) $file); Assert::exception(function () { (new Extractor('')); diff --git a/tests/PhpGenerator/expected/Extractor.expect b/tests/PhpGenerator/expected/Extractor.expect new file mode 100644 index 00000000..dc56a7e3 --- /dev/null +++ b/tests/PhpGenerator/expected/Extractor.expect @@ -0,0 +1,22 @@ + Date: Tue, 4 Oct 2022 13:22:53 +0200 Subject: [PATCH 03/15] Extractor: keeps the first comment in the method [Closes #119] --- src/PhpGenerator/Extractor.php | 12 +++++++++-- .../expected/ClassType.from.bodies.expect | 2 ++ .../expected/Extractor.bodies.expect | 2 ++ .../Extractor.bodies.resolving.expect | 2 ++ .../Extractor.bodies.unresolving.expect | 2 ++ tests/PhpGenerator/expected/Extractor.expect | 21 +++++++++++++++++++ tests/PhpGenerator/fixtures/extractor.php | 18 ++++++++++++++++ 7 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/PhpGenerator/Extractor.php b/src/PhpGenerator/Extractor.php index d5569f4c..eb52a87b 100644 --- a/src/PhpGenerator/Extractor.php +++ b/src/PhpGenerator/Extractor.php @@ -108,7 +108,7 @@ private function getReformattedContents(array $nodes, int $level): string */ private function prepareReplacements(array $nodes): array { - $start = $nodes[0]->getStartFilePos(); + $start = $this->getNodeStartPos($nodes[0]); $replacements = []; (new NodeFinder)->find($nodes, function (Node $node) use (&$replacements, $start) { if ($node instanceof Node\Name\FullyQualified) { @@ -430,7 +430,15 @@ private function toPhp(mixed $value): string private function getNodeContents(Node ...$nodes): string { - $start = $nodes[0]->getStartFilePos(); + $start = $this->getNodeStartPos($nodes[0]); return substr($this->code, $start, end($nodes)->getEndFilePos() - $start + 1); } + + + private function getNodeStartPos(Node $node): int + { + return ($comments = $node->getComments()) + ? $comments[0]->getStartFilePos() + : $node->getStartFilePos(); + } } diff --git a/tests/PhpGenerator/expected/ClassType.from.bodies.expect b/tests/PhpGenerator/expected/ClassType.from.bodies.expect index 1ce8fe8f..a251549e 100644 --- a/tests/PhpGenerator/expected/ClassType.from.bodies.expect +++ b/tests/PhpGenerator/expected/ClassType.from.bodies.expect @@ -27,6 +27,7 @@ abstract class Class7 public function long() { + // comment if ($member instanceof Method) { $s = [1, 2, 3]; } @@ -39,6 +40,7 @@ abstract class Class7 public function resolving($a = Abc\a\FOO, self $b = null, $c = self::FOO) { + // constants echo FOO; echo \FOO; echo a\FOO; diff --git a/tests/PhpGenerator/expected/Extractor.bodies.expect b/tests/PhpGenerator/expected/Extractor.bodies.expect index 21d22313..6e321ade 100644 --- a/tests/PhpGenerator/expected/Extractor.bodies.expect +++ b/tests/PhpGenerator/expected/Extractor.bodies.expect @@ -37,6 +37,7 @@ abstract class Class7 function long() { + // comment if ($member instanceof Method) { $s = [1, 2, 3]; } @@ -49,6 +50,7 @@ abstract class Class7 function resolving($a = a\FOO, self $b = null, $c = self::FOO) { + // constants echo FOO; echo \FOO; echo a\FOO; diff --git a/tests/PhpGenerator/expected/Extractor.bodies.resolving.expect b/tests/PhpGenerator/expected/Extractor.bodies.resolving.expect index efe51b99..cb64aca7 100644 --- a/tests/PhpGenerator/expected/Extractor.bodies.resolving.expect +++ b/tests/PhpGenerator/expected/Extractor.bodies.resolving.expect @@ -32,6 +32,7 @@ abstract class Class7 function long() { + // comment if ($member instanceof \Abc\Method) { $s = [1, 2, 3]; } @@ -44,6 +45,7 @@ abstract class Class7 function resolving($a = \Abc\a\FOO, self $b = null, $c = self::FOO) { + // constants echo FOO; echo \FOO; echo \Abc\a\FOO; diff --git a/tests/PhpGenerator/expected/Extractor.bodies.unresolving.expect b/tests/PhpGenerator/expected/Extractor.bodies.unresolving.expect index 8d8a774c..6ae6f85c 100644 --- a/tests/PhpGenerator/expected/Extractor.bodies.unresolving.expect +++ b/tests/PhpGenerator/expected/Extractor.bodies.unresolving.expect @@ -32,6 +32,7 @@ abstract class Class7 function long() { + // comment if ($member instanceof \Abc\Method) { $s = [1, 2, 3]; } @@ -44,6 +45,7 @@ abstract class Class7 function resolving($a = \Abc\a\FOO, self $b = null, $c = self::FOO) { + // constants echo FOO; echo \FOO; echo \Abc\a\FOO; diff --git a/tests/PhpGenerator/expected/Extractor.expect b/tests/PhpGenerator/expected/Extractor.expect index dc56a7e3..8b3afc30 100644 --- a/tests/PhpGenerator/expected/Extractor.expect +++ b/tests/PhpGenerator/expected/Extractor.expect @@ -9,6 +9,27 @@ class Class1 } }; } + + + function comment1() + { + /** comment */ + $a = 10; + } + + + function comment2() + { + // comment + "bar"; + } + + + function comment3() + { + // comment + Foo\Bar::XX; + } } /** diff --git a/tests/PhpGenerator/fixtures/extractor.php b/tests/PhpGenerator/fixtures/extractor.php index 2566fac7..fafe8004 100644 --- a/tests/PhpGenerator/fixtures/extractor.php +++ b/tests/PhpGenerator/fixtures/extractor.php @@ -8,6 +8,24 @@ function bar() { } }; } + + function comment1() + { + /** comment */ + $a = 10; + } + + function comment2() + { + // comment + 'bar'; + } + + function comment3() + { + // comment + Foo\Bar::XX; + } } function () {}; From f7a109a4f9c12fe7bb573b972501f53d4ab57cdb Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 02:20:22 +0200 Subject: [PATCH 04/15] Type: constants are PascalCase --- readme.md | 2 +- src/PhpGenerator/Type.php | 51 +++++++++++++------ tests/PhpGenerator/ClassType.phpt | 8 +-- .../PhpGenerator/Method.scalarParameters.phpt | 4 +- tests/PhpGenerator/Type.phpt | 2 +- 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/readme.md b/readme.md index 8cd138d3..d8909baa 100644 --- a/readme.md +++ b/readme.md @@ -502,7 +502,7 @@ Each type or union/intersection type can be passed as a string, you can also use ```php use Nette\PhpGenerator\Type; -$member->setType('array'); // or Type::ARRAY; +$member->setType('array'); // or Type::Array; $member->setType('array|string'); // or Type::union('array', 'string') $member->setType('Foo&Bar'); // or Type::intersection(Foo::class, Bar::class) $member->setType(null); // removes type diff --git a/src/PhpGenerator/Type.php b/src/PhpGenerator/Type.php index be77199d..724e35fb 100644 --- a/src/PhpGenerator/Type.php +++ b/src/PhpGenerator/Type.php @@ -16,22 +16,41 @@ class Type { public const - STRING = 'string', - INT = 'int', - FLOAT = 'float', - BOOL = 'bool', - ARRAY = 'array', - OBJECT = 'object', - CALLABLE = 'callable', - ITERABLE = 'iterable', - VOID = 'void', - NEVER = 'never', - MIXED = 'mixed', - FALSE = 'false', - NULL = 'null', - SELF = 'self', - PARENT = 'parent', - STATIC = 'static'; + String = 'string', + Int = 'int', + Float = 'float', + Bool = 'bool', + Array = 'array', + Object = 'object', + Callable = 'callable', + Iterable = 'iterable', + Void = 'void', + Never = 'never', + Mixed = 'mixed', + False = 'false', + Null = 'null', + Self = 'self', + Parent = 'parent', + Static = 'static'; + + /** @deprecated */ + public const + STRING = self::String, + INT = self::Int, + FLOAT = self::Float, + BOOL = self::Bool, + ARRAY = self::Array, + OBJECT = self::Object, + CALLABLE = self::Callable, + ITERABLE = self::Iterable, + VOID = self::Void, + NEVER = self::Never, + MIXED = self::Mixed, + FALSE = self::False, + NULL = self::Null, + SELF = self::Self, + PARENT = self::Parent, + STATIC = self::Static; public static function nullable(string $type, bool $state = true): string diff --git a/tests/PhpGenerator/ClassType.phpt b/tests/PhpGenerator/ClassType.phpt index 1ec06192..cc6c2a4f 100644 --- a/tests/PhpGenerator/ClassType.phpt +++ b/tests/PhpGenerator/ClassType.phpt @@ -60,16 +60,16 @@ $class->addProperty('order') ->setValue(new Literal('RecursiveIteratorIterator::SELF_FIRST')); $class->addProperty('typed1') - ->setType(Type::ARRAY) + ->setType(Type::Array) ->setReadOnly(); $class->addProperty('typed2') - ->setType(Type::ARRAY) + ->setType(Type::Array) ->setNullable() ->setInitialized(); $class->addProperty('typed3') - ->setType(Type::ARRAY) + ->setType(Type::Array) ->setValue(null); $p = $class->addProperty('sections', ['first' => true]) @@ -128,7 +128,7 @@ $method->addParameter('item'); $method->addParameter('res', null) ->setReference(true) - ->setType(Type::union(Type::ARRAY, 'null')); + ->setType(Type::union(Type::Array, 'null')); $method->addParameter('bar', null) ->setType('stdClass|string') diff --git a/tests/PhpGenerator/Method.scalarParameters.phpt b/tests/PhpGenerator/Method.scalarParameters.phpt index 0b11c876..2cb36a86 100644 --- a/tests/PhpGenerator/Method.scalarParameters.phpt +++ b/tests/PhpGenerator/Method.scalarParameters.phpt @@ -39,8 +39,8 @@ Assert::same('float', $method->getParameters()['d']->getType()); $method = (new Method('create')) ->setBody('return null;'); -$method->addParameter('a')->setType(Type::STRING); -$method->addParameter('b')->setType(Type::BOOL); +$method->addParameter('a')->setType(Type::String); +$method->addParameter('b')->setType(Type::Bool); same( 'function create(string $a, bool $b) diff --git a/tests/PhpGenerator/Type.phpt b/tests/PhpGenerator/Type.phpt index 84626f77..f889865a 100644 --- a/tests/PhpGenerator/Type.phpt +++ b/tests/PhpGenerator/Type.phpt @@ -8,7 +8,7 @@ use Tester\Assert; require __DIR__ . '/../bootstrap.php'; -Assert::same('A|string', Type::union(A::class, Type::STRING)); +Assert::same('A|string', Type::union(A::class, Type::String)); Assert::same('?A', Type::nullable(A::class)); Assert::same('?A', Type::nullable(A::class, true)); From 1769a2e286fca8df016b39debf51133d4466074e Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 02:47:24 +0200 Subject: [PATCH 05/15] added Type::True --- src/PhpGenerator/Type.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpGenerator/Type.php b/src/PhpGenerator/Type.php index 724e35fb..be3242a4 100644 --- a/src/PhpGenerator/Type.php +++ b/src/PhpGenerator/Type.php @@ -27,6 +27,7 @@ class Type Void = 'void', Never = 'never', Mixed = 'mixed', + True = 'true', False = 'false', Null = 'null', Self = 'self', From c93ab11b70e9aae0ff63cae4325f4e7ce6e1d247 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 02:31:08 +0200 Subject: [PATCH 06/15] added support for readonly classes --- composer.json | 4 ++-- readme.md | 2 +- src/PhpGenerator/ClassType.php | 14 ++++++++++++++ src/PhpGenerator/Extractor.php | 1 + src/PhpGenerator/Factory.php | 1 + src/PhpGenerator/Printer.php | 1 + tests/PhpGenerator/ClassType.from.82.phpt | 17 +++++++++++++++++ tests/PhpGenerator/Extractor.extractAll.phpt | 3 +++ .../expected/ClassType.from.82.expect | 3 +++ .../expected/Extractor.classes.82.expect | 9 +++++++++ tests/PhpGenerator/fixtures/classes.82.php | 9 +++++++++ 11 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 tests/PhpGenerator/ClassType.from.82.phpt create mode 100644 tests/PhpGenerator/expected/ClassType.from.82.expect create mode 100644 tests/PhpGenerator/expected/Extractor.classes.82.expect create mode 100644 tests/PhpGenerator/fixtures/classes.82.php diff --git a/composer.json b/composer.json index 431cbc9b..9f79b3be 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "nette/php-generator", - "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.1 features.", + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.2 features.", "keywords": ["nette", "php", "code", "scaffolding"], "homepage": "https://nette.org", "license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"], @@ -20,7 +20,7 @@ }, "require-dev": { "nette/tester": "^2.4", - "nikic/php-parser": "^4.13", + "nikic/php-parser": "^4.14", "tracy/tracy": "^2.8", "phpstan/phpstan": "^1.0" }, diff --git a/readme.md b/readme.md index d8909baa..01f74159 100644 --- a/readme.md +++ b/readme.md @@ -141,7 +141,7 @@ public function __construct( } ``` -Readonly properties introduced by PHP 8.1 can be marked via `setReadOnly()`. +Readonly properties and classes can be marked via `setReadOnly()`. ------ diff --git a/src/PhpGenerator/ClassType.php b/src/PhpGenerator/ClassType.php index a78a1d8b..1877d163 100644 --- a/src/PhpGenerator/ClassType.php +++ b/src/PhpGenerator/ClassType.php @@ -36,6 +36,7 @@ final class ClassType extends ClassLike private bool $final = false; private bool $abstract = false; private ?string $extends = null; + private bool $readOnly = false; /** @var string[] */ private array $implements = []; @@ -172,6 +173,19 @@ public function isAbstract(): bool } + public function setReadOnly(bool $state = true): static + { + $this->readOnly = $state; + return $this; + } + + + public function isReadOnly(): bool + { + return $this->readOnly; + } + + public function setExtends(?string $name): static { if ($name) { diff --git a/src/PhpGenerator/Extractor.php b/src/PhpGenerator/Extractor.php index eb52a87b..f2054fcd 100644 --- a/src/PhpGenerator/Extractor.php +++ b/src/PhpGenerator/Extractor.php @@ -246,6 +246,7 @@ private function addClassToFile(PhpFile $phpFile, Node\Stmt\Class_ $node): Class $class->setFinal($node->isFinal()); $class->setAbstract($node->isAbstract()); + $class->setReadOnly(method_exists($node, 'isReadonly') && $node->isReadonly()); $this->addCommentAndAttributes($class, $node); return $class; } diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 3d6706c4..9d3893ea 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -55,6 +55,7 @@ public function fromClassReflection( $class = new ClassType($from->getShortName(), new PhpNamespace($from->getNamespaceName())); $class->setFinal($from->isFinal() && $class->isClass()); $class->setAbstract($from->isAbstract() && $class->isClass()); + $class->setReadOnly(PHP_VERSION_ID >= 80200 && $from->isReadOnly()); } $ifaces = $from->getInterfaceNames(); diff --git a/src/PhpGenerator/Printer.php b/src/PhpGenerator/Printer.php index 57718375..9847fbaf 100644 --- a/src/PhpGenerator/Printer.php +++ b/src/PhpGenerator/Printer.php @@ -226,6 +226,7 @@ public function printClass( if ($class instanceof ClassType) { $line[] = $class->isAbstract() ? 'abstract' : null; $line[] = $class->isFinal() ? 'final' : null; + $line[] = $class->isReadOnly() ? 'readonly' : null; } $line[] = match (true) { diff --git a/tests/PhpGenerator/ClassType.from.82.phpt b/tests/PhpGenerator/ClassType.from.82.phpt new file mode 100644 index 00000000..5acddad0 --- /dev/null +++ b/tests/PhpGenerator/ClassType.from.82.phpt @@ -0,0 +1,17 @@ +extractAll(); sameFile(__DIR__ . '/expected/Extractor.classes.81.expect', (string) $file); +$file = (new Extractor(file_get_contents(__DIR__ . '/fixtures/classes.82.php')))->extractAll(); +sameFile(__DIR__ . '/expected/Extractor.classes.82.expect', (string) $file); + $file = (new Extractor(file_get_contents(__DIR__ . '/fixtures/enum.php')))->extractAll(); sameFile(__DIR__ . '/expected/Extractor.enum.expect', (string) $file); diff --git a/tests/PhpGenerator/expected/ClassType.from.82.expect b/tests/PhpGenerator/expected/ClassType.from.82.expect new file mode 100644 index 00000000..39bb4484 --- /dev/null +++ b/tests/PhpGenerator/expected/ClassType.from.82.expect @@ -0,0 +1,3 @@ +readonly class Class13 +{ +} diff --git a/tests/PhpGenerator/expected/Extractor.classes.82.expect b/tests/PhpGenerator/expected/Extractor.classes.82.expect new file mode 100644 index 00000000..ea812871 --- /dev/null +++ b/tests/PhpGenerator/expected/Extractor.classes.82.expect @@ -0,0 +1,9 @@ + Date: Tue, 4 Oct 2022 02:56:46 +0200 Subject: [PATCH 07/15] added support for constants in traits --- src/PhpGenerator/Printer.php | 16 +++++++--------- src/PhpGenerator/TraitType.php | 3 +++ tests/PhpGenerator/ClassType.from.82.phpt | 1 + .../expected/ClassType.from.82.expect | 5 +++++ .../expected/Extractor.classes.82.expect | 5 +++++ tests/PhpGenerator/fixtures/classes.82.php | 6 ++++++ 6 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/PhpGenerator/Printer.php b/src/PhpGenerator/Printer.php index 9847fbaf..dbd56ad8 100644 --- a/src/PhpGenerator/Printer.php +++ b/src/PhpGenerator/Printer.php @@ -167,7 +167,13 @@ public function printClass( } $consts = []; - if ($class instanceof ClassType || $class instanceof InterfaceType || $class instanceof EnumType) { + $methods = []; + if ( + $class instanceof ClassType + || $class instanceof InterfaceType + || $class instanceof TraitType + || $class instanceof EnumType + ) { foreach ($class->getConstants() as $const) { $def = ($const->isFinal() ? 'final ' : '') . ($const->getVisibility() ? $const->getVisibility() . ' ' : '') @@ -178,15 +184,7 @@ public function printClass( . $def . $this->dump($const->getValue(), strlen($def)) . ";\n"; } - } - $methods = []; - if ( - $class instanceof ClassType - || $class instanceof InterfaceType - || $class instanceof EnumType - || $class instanceof TraitType - ) { foreach ($class->getMethods() as $method) { $methods[] = $this->printMethod($method, $namespace, $class->isInterface()); } diff --git a/src/PhpGenerator/TraitType.php b/src/PhpGenerator/TraitType.php index 4dbf42df..57621ad4 100644 --- a/src/PhpGenerator/TraitType.php +++ b/src/PhpGenerator/TraitType.php @@ -20,6 +20,7 @@ */ final class TraitType extends ClassLike { + use Traits\ConstantsAware; use Traits\MethodsAware; use Traits\PropertiesAware; use Traits\TraitsAware; @@ -28,6 +29,7 @@ public function addMember(Method|Property|Constant|TraitUse $member): static { $name = $member->getName(); [$type, $n] = match (true) { + $member instanceof Constant => ['consts', $name], $member instanceof Method => ['methods', strtolower($name)], $member instanceof Property => ['properties', $name], $member instanceof TraitUse => ['traits', $name], @@ -43,6 +45,7 @@ public function addMember(Method|Property|Constant|TraitUse $member): static public function __clone() { $clone = fn($item) => clone $item; + $this->consts = array_map($clone, $this->consts); $this->methods = array_map($clone, $this->methods); $this->properties = array_map($clone, $this->properties); $this->traits = array_map($clone, $this->traits); diff --git a/tests/PhpGenerator/ClassType.from.82.phpt b/tests/PhpGenerator/ClassType.from.82.phpt index 5acddad0..db001ac7 100644 --- a/tests/PhpGenerator/ClassType.from.82.phpt +++ b/tests/PhpGenerator/ClassType.from.82.phpt @@ -13,5 +13,6 @@ require __DIR__ . '/../bootstrap.php'; require __DIR__ . '/fixtures/classes.82.php'; $res[] = ClassType::from(new Abc\Class13); +$res[] = ClassType::from(Abc\Trait13::class); sameFile(__DIR__ . '/expected/ClassType.from.82.expect', implode("\n", $res)); diff --git a/tests/PhpGenerator/expected/ClassType.from.82.expect b/tests/PhpGenerator/expected/ClassType.from.82.expect index 39bb4484..4c03d053 100644 --- a/tests/PhpGenerator/expected/ClassType.from.82.expect +++ b/tests/PhpGenerator/expected/ClassType.from.82.expect @@ -1,3 +1,8 @@ readonly class Class13 { } + +trait Trait13 +{ + public const FOO = 123; +} diff --git a/tests/PhpGenerator/expected/Extractor.classes.82.expect b/tests/PhpGenerator/expected/Extractor.classes.82.expect index ea812871..c7de3d7e 100644 --- a/tests/PhpGenerator/expected/Extractor.classes.82.expect +++ b/tests/PhpGenerator/expected/Extractor.classes.82.expect @@ -7,3 +7,8 @@ namespace Abc; readonly class Class13 { } + +trait Trait13 +{ + public const FOO = 123; +} diff --git a/tests/PhpGenerator/fixtures/classes.82.php b/tests/PhpGenerator/fixtures/classes.82.php index ea812871..95e594ff 100644 --- a/tests/PhpGenerator/fixtures/classes.82.php +++ b/tests/PhpGenerator/fixtures/classes.82.php @@ -7,3 +7,9 @@ readonly class Class13 { } + + +trait Trait13 +{ + public const FOO = 123; +} From 8959ed25d80317b0575e7eae7d157794f5d9cada Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 03:07:10 +0200 Subject: [PATCH 08/15] added support for DNF types --- composer.json | 2 +- src/PhpGenerator/Helpers.php | 13 ++++-- tests/PhpGenerator/Helpers.validateType.phpt | 43 +++++++++++++++++++ .../expected/ClassType.from.82.expect | 3 ++ .../expected/Extractor.classes.82.expect | 3 ++ tests/PhpGenerator/fixtures/classes.82.php | 3 ++ 6 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/PhpGenerator/Helpers.validateType.phpt diff --git a/composer.json b/composer.json index 9f79b3be..fc193a79 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ }, "require-dev": { "nette/tester": "^2.4", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.15", "tracy/tracy": "^2.8", "phpstan/phpstan": "^1.0" }, diff --git a/src/PhpGenerator/Helpers.php b/src/PhpGenerator/Helpers.php index 71e7de6f..12823b4c 100644 --- a/src/PhpGenerator/Helpers.php +++ b/src/PhpGenerator/Helpers.php @@ -170,14 +170,19 @@ public static function createObject(string $class, array $props): object public static function validateType(?string $type, bool &$nullable): ?string { + $nullable = false; if ($type === '' || $type === null) { return null; } - if (!preg_match('#(?: - \?[\w\\\\]+| - [\w\\\\]+ (?: (&[\w\\\\]+)* | (\|[\w\\\\]+)* ) - )()$#xAD', $type)) { + if (!preg_match(<<<'XX' + ~(?n) + ( + \?? (? [\w\\]+)| + (? (?&type) (& (?&type))+ )| + (? (?&type) | \( (?&intersection) \) ) (\| (?&upart) )+ + )$~xAD + XX, $type)) { throw new Nette\InvalidArgumentException("Value '$type' is not valid type."); } diff --git a/tests/PhpGenerator/Helpers.validateType.phpt b/tests/PhpGenerator/Helpers.validateType.phpt new file mode 100644 index 00000000..1277ca8f --- /dev/null +++ b/tests/PhpGenerator/Helpers.validateType.phpt @@ -0,0 +1,43 @@ + Helpers::validateType('-', $foo), + Nette\InvalidArgumentException::class, +); + +Assert::exception( + fn() => Helpers::validateType('?Foo|Bar', $foo), + Nette\InvalidArgumentException::class, +); + +Assert::exception( + fn() => Helpers::validateType('(Foo)', $foo), + Nette\InvalidArgumentException::class, +); + +Assert::exception( + fn() => Helpers::validateType('(Foo&Bar)', $foo), + Nette\InvalidArgumentException::class, +); diff --git a/tests/PhpGenerator/expected/ClassType.from.82.expect b/tests/PhpGenerator/expected/ClassType.from.82.expect index 4c03d053..6ea6378a 100644 --- a/tests/PhpGenerator/expected/ClassType.from.82.expect +++ b/tests/PhpGenerator/expected/ClassType.from.82.expect @@ -1,5 +1,8 @@ readonly class Class13 { + public function func(C|(X&D)|null $foo): (A&B)|null + { + } } trait Trait13 diff --git a/tests/PhpGenerator/expected/Extractor.classes.82.expect b/tests/PhpGenerator/expected/Extractor.classes.82.expect index c7de3d7e..54f5c525 100644 --- a/tests/PhpGenerator/expected/Extractor.classes.82.expect +++ b/tests/PhpGenerator/expected/Extractor.classes.82.expect @@ -6,6 +6,9 @@ namespace Abc; readonly class Class13 { + public function func(C|(X&D)|null $foo): (A&B)|null + { + } } trait Trait13 diff --git a/tests/PhpGenerator/fixtures/classes.82.php b/tests/PhpGenerator/fixtures/classes.82.php index 95e594ff..ae22c11e 100644 --- a/tests/PhpGenerator/fixtures/classes.82.php +++ b/tests/PhpGenerator/fixtures/classes.82.php @@ -6,6 +6,9 @@ readonly class Class13 { + public function func(C|(X&D)|null $foo): (A&B)|null + { + } } From 2275acae366c3c4d38b9e7de2d41c9f871b58417 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 14:14:48 +0200 Subject: [PATCH 09/15] updated github workflow --- .github/workflows/coding-style.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml index 973c7a12..ab9c647a 100644 --- a/.github/workflows/coding-style.yml +++ b/.github/workflows/coding-style.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: shivammathur/setup-php@v1 + - uses: shivammathur/setup-php@v2 with: php-version: 8.0 coverage: none @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: shivammathur/setup-php@v1 + - uses: shivammathur/setup-php@v2 with: php-version: 8.0 coverage: none From 80f158a2d2fa44c1785b16a3dcdabef3120b3e71 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 6 Oct 2022 23:13:58 +0200 Subject: [PATCH 10/15] PhpNamespace: better use-statements sorting behavior --- src/PhpGenerator/PhpNamespace.php | 2 +- tests/PhpGenerator/Printer.use-order.phpt | 28 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 tests/PhpGenerator/Printer.use-order.phpt diff --git a/src/PhpGenerator/PhpNamespace.php b/src/PhpGenerator/PhpNamespace.php index 890fc8bf..660ff026 100644 --- a/src/PhpGenerator/PhpNamespace.php +++ b/src/PhpGenerator/PhpNamespace.php @@ -162,7 +162,7 @@ public function addUseConstant(string $name, ?string $alias = null): static /** @return string[] */ public function getUses(string $of = self::NameNormal): array { - asort($this->aliases[$of]); + uasort($this->aliases[$of], fn(string $a, string $b): int => strtr($a, '\\', ' ') <=> strtr($b, '\\', ' ')); return array_filter( $this->aliases[$of], fn($name, $alias) => strcasecmp(($this->name ? $this->name . '\\' : '') . $alias, $name), diff --git a/tests/PhpGenerator/Printer.use-order.phpt b/tests/PhpGenerator/Printer.use-order.phpt new file mode 100644 index 00000000..f7e642eb --- /dev/null +++ b/tests/PhpGenerator/Printer.use-order.phpt @@ -0,0 +1,28 @@ +addUse('Example\Foo\EmailAlias\Bar'); +$namespace->addUse('Example\Foo\Email\Test'); +$namespace->addUse('Example\Foo\MyClass'); + +Assert::match( + <<<'XX' + namespace Foo; + + use Example\Foo\Email\Test; + use Example\Foo\EmailAlias\Bar; + use Example\Foo\MyClass; + + XX, + $printer->printNamespace($namespace), +); From c15a6a4398f891600f0548eaaa2597390f338959 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 13 Oct 2022 01:45:22 +0200 Subject: [PATCH 11/15] cs --- src/PhpGenerator/Factory.php | 3 ++- src/PhpGenerator/Printer.php | 3 ++- tests/PhpGenerator/Method.returnTypes.phpt | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 9d3893ea..33c6f115 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -32,7 +32,8 @@ public function fromClassReflection( \ReflectionClass $from, bool $withBodies = false, ?bool $materializeTraits = null, - ): ClassLike { + ): ClassLike + { if ($materializeTraits !== null) { trigger_error(__METHOD__ . '() parameter $materializeTraits has been removed (is always false).', E_USER_DEPRECATED); } diff --git a/src/PhpGenerator/Printer.php b/src/PhpGenerator/Printer.php index dbd56ad8..c7005fe1 100644 --- a/src/PhpGenerator/Printer.php +++ b/src/PhpGenerator/Printer.php @@ -133,7 +133,8 @@ public function printMethod(Method $method, ?PhpNamespace $namespace = null, boo public function printClass( ClassType|InterfaceType|TraitType|EnumType $class, ?PhpNamespace $namespace = null, - ): string { + ): string + { $this->namespace = $this->resolveTypes ? $namespace : null; $class->validate(); $resolver = $this->namespace diff --git a/tests/PhpGenerator/Method.returnTypes.phpt b/tests/PhpGenerator/Method.returnTypes.phpt index 10b67c68..bdde645b 100644 --- a/tests/PhpGenerator/Method.returnTypes.phpt +++ b/tests/PhpGenerator/Method.returnTypes.phpt @@ -13,8 +13,7 @@ namespace A } } -namespace -{ +namespace { use Nette\PhpGenerator\Method; use Tester\Assert; From 9c200fac49e033a95d84baa3cba1e0d4e00a1233 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 13 Oct 2022 01:46:29 +0200 Subject: [PATCH 12/15] updated github workflow --- .github/workflows/coding-style.yml | 4 ++-- .github/workflows/static-analysis.yml | 2 +- .github/workflows/tests.yml | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml index ab9c647a..875287f8 100644 --- a/.github/workflows/coding-style.yml +++ b/.github/workflows/coding-style.yml @@ -7,7 +7,7 @@ jobs: name: Nette Code Checker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: 8.0 @@ -21,7 +21,7 @@ jobs: name: Nette Coding Standard runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: 8.0 diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 94b3ec65..25e44dd0 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -7,7 +7,7 @@ jobs: name: PHPStan runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: 8.0 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 54206dba..239bdc4d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: name: PHP ${{ matrix.php }} tests steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} @@ -22,7 +22,7 @@ jobs: - run: composer install --no-progress --prefer-dist - run: vendor/bin/tester tests -s -C - if: failure() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: output path: tests/**/output @@ -32,7 +32,7 @@ jobs: name: Lowest Dependencies runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: 8.0 @@ -46,7 +46,7 @@ jobs: name: Code Coverage runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: shivammathur/setup-php@v2 with: php-version: 8.0 From d43ee73f58482651b2e23f4bd59642e5d03a81be Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 04:09:58 +0200 Subject: [PATCH 13/15] updated phpstan baseline --- phpstan-baseline.neon | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dd03b4fa..c826bc8e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: '#^Match expression does not handle remaining value\: true$#' - count: 1 - path: src/PhpGenerator/ClassLike.php - - message: '#^Method Nette\\PhpGenerator\\ClassType\:\:addTrait\(\) has parameter \$deprecatedParam with no value type specified in iterable type array\.$#' count: 1 @@ -15,16 +10,6 @@ parameters: count: 1 path: src/PhpGenerator/EnumType.php - - - message: '#^Access to an undefined property PhpParser\\Node\:\:\$attrGroups\.$#' - count: 1 - path: src/PhpGenerator/Extractor.php - - - - message: '#^Access to an undefined property PhpParser\\Node\\Expr\:\:\$value\.$#' - count: 1 - path: src/PhpGenerator/Extractor.php - - message: '#^Call to an undefined method Nette\\PhpGenerator\\ClassLike\:\:addConstant\(\)\.$#' count: 1 @@ -45,13 +30,18 @@ parameters: count: 1 path: src/PhpGenerator/Extractor.php + - + message: '#^Call to an undefined method Nette\\PhpGenerator\\FunctionLike\:\:addPromotedParameter\(\)\.$#' + count: 1 + path: src/PhpGenerator/Extractor.php + - message: '#^Method Nette\\PhpGenerator\\Extractor\:\:addCommentAndAttributes\(\) has parameter \$element with no type specified\.$#' count: 1 path: src/PhpGenerator/Extractor.php - - message: '#^Property class@anonymous/PhpGenerator/Extractor\.php\:176\:\:\$callback has no type specified\.$#' + message: '#^Property class@anonymous/PhpGenerator/Extractor\.php\:175\:\:\$callback has no type specified\.$#' count: 1 path: src/PhpGenerator/Extractor.php @@ -65,6 +55,11 @@ parameters: count: 1 path: src/PhpGenerator/Factory.php + - + message: '#^Call to an undefined method ReflectionClass\\:\:isReadOnly\(\)\.$#' + count: 1 + path: src/PhpGenerator/Factory.php + - message: '#^Elseif branch is unreachable because previous condition is always true\.$#' count: 1 @@ -90,11 +85,6 @@ parameters: count: 1 path: src/PhpGenerator/Factory.php - - - message: '#^Parameter \#1 \$name of method Nette\\PhpGenerator\\ClassType\:\:setExtends\(\) expects string\|null, array\ given\.$#' - count: 1 - path: src/PhpGenerator/Factory.php - - message: '#^Unreachable statement \- code above always terminates\.$#' count: 1 @@ -115,6 +105,11 @@ parameters: count: 1 path: src/PhpGenerator/Method.php + - + message: '#^Method Nette\\PhpGenerator\\Printer\:\:printDocComment\(\) has parameter \$commentable with no type specified\.$#' + count: 1 + path: src/PhpGenerator/Printer.php + - message: '#^Method Nette\\PhpGenerator\\TraitType\:\:addTrait\(\) has parameter \$deprecatedParam with no value type specified in iterable type array\.$#' count: 1 From 676b60c0cc47a3ad2312b5c75a4ebda1bb560bc0 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 4 Oct 2022 01:50:48 +0200 Subject: [PATCH 14/15] FunctionLike changed to abstract class --- src/PhpGenerator/Closure.php | 5 +---- src/PhpGenerator/Extractor.php | 2 +- src/PhpGenerator/Factory.php | 2 +- src/PhpGenerator/{Traits => }/FunctionLike.php | 10 +++++----- src/PhpGenerator/GlobalFunction.php | 5 +---- src/PhpGenerator/Method.php | 11 ++++++----- src/PhpGenerator/Printer.php | 2 +- 7 files changed, 16 insertions(+), 21 deletions(-) rename src/PhpGenerator/{Traits => }/FunctionLike.php (95%) diff --git a/src/PhpGenerator/Closure.php b/src/PhpGenerator/Closure.php index 398e1491..d019fbd6 100644 --- a/src/PhpGenerator/Closure.php +++ b/src/PhpGenerator/Closure.php @@ -14,13 +14,10 @@ /** * Closure. - * - * @property-deprecated string $body */ -final class Closure +final class Closure extends FunctionLike { use Nette\SmartObject; - use Traits\FunctionLike; use Traits\AttributeAware; /** @var Parameter[] */ diff --git a/src/PhpGenerator/Extractor.php b/src/PhpGenerator/Extractor.php index f2054fcd..148bf3a4 100644 --- a/src/PhpGenerator/Extractor.php +++ b/src/PhpGenerator/Extractor.php @@ -385,7 +385,7 @@ private function addCommentAndAttributes($element, Node $node): void } - private function setupFunction(GlobalFunction|Method $function, Node\FunctionLike $node): void + private function setupFunction(FunctionLike $function, Node\FunctionLike $node): void { $function->setReturnReference($node->returnsByRef()); $function->setReturnType($node->getReturnType() ? $this->toPhp($node->getReturnType()) : null); diff --git a/src/PhpGenerator/Factory.php b/src/PhpGenerator/Factory.php index 33c6f115..c8193a59 100644 --- a/src/PhpGenerator/Factory.php +++ b/src/PhpGenerator/Factory.php @@ -194,7 +194,7 @@ public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody } - public function fromCallable(callable $from): Method|GlobalFunction|Closure + public function fromCallable(callable $from): FunctionLike { $ref = Nette\Utils\Callback::toReflection($from); return $ref instanceof \ReflectionMethod diff --git a/src/PhpGenerator/Traits/FunctionLike.php b/src/PhpGenerator/FunctionLike.php similarity index 95% rename from src/PhpGenerator/Traits/FunctionLike.php rename to src/PhpGenerator/FunctionLike.php index 15bb8e57..ace264ce 100644 --- a/src/PhpGenerator/Traits/FunctionLike.php +++ b/src/PhpGenerator/FunctionLike.php @@ -7,18 +7,18 @@ declare(strict_types=1); -namespace Nette\PhpGenerator\Traits; +namespace Nette\PhpGenerator; use Nette; -use Nette\PhpGenerator\Dumper; -use Nette\PhpGenerator\Parameter; use Nette\Utils\Type; /** - * @internal + * GlobalFunction/Closure/Method description. + * + * @property-deprecated string $body */ -trait FunctionLike +abstract class FunctionLike { private string $body = ''; diff --git a/src/PhpGenerator/GlobalFunction.php b/src/PhpGenerator/GlobalFunction.php index ae1e4f88..26665332 100644 --- a/src/PhpGenerator/GlobalFunction.php +++ b/src/PhpGenerator/GlobalFunction.php @@ -14,13 +14,10 @@ /** * Global function. - * - * @property-deprecated string $body */ -final class GlobalFunction +final class GlobalFunction extends FunctionLike { use Nette\SmartObject; - use Traits\FunctionLike; use Traits\NameAware; use Traits\CommentAware; use Traits\AttributeAware; diff --git a/src/PhpGenerator/Method.php b/src/PhpGenerator/Method.php index 0596658c..fbffab1f 100644 --- a/src/PhpGenerator/Method.php +++ b/src/PhpGenerator/Method.php @@ -14,13 +14,10 @@ /** * Class method. - * - * @property-deprecated string|null $body */ -final class Method +final class Method extends FunctionLike { use Nette\SmartObject; - use Traits\FunctionLike; use Traits\NameAware; use Traits\VisibilityAware; use Traits\CommentAware; @@ -92,7 +89,11 @@ public function addPromotedParameter(string $name, mixed $defaultValue = null): $param->setDefaultValue($defaultValue); } - return $this->parameters[$name] = $param; + $params = $this->getParameters(); + $params[$name] = $param; + $this->setParameters($params); + + return $param; } diff --git a/src/PhpGenerator/Printer.php b/src/PhpGenerator/Printer.php index c7005fe1..4e0f3ee3 100644 --- a/src/PhpGenerator/Printer.php +++ b/src/PhpGenerator/Printer.php @@ -385,7 +385,7 @@ protected function printDocComment(/*Traits\CommentAware*/ $commentable): string } - private function printReturnType(Closure|GlobalFunction|Method $function): string + private function printReturnType(FunctionLike $function): string { return ($tmp = $this->printType($function->getReturnType(), $function->isReturnNullable())) ? $this->returnTypeColon . $tmp From 0b566eed4c5dce5b4154bcf12885246f516d2ca4 Mon Sep 17 00:00:00 2001 From: Jeroen <1517978+Jeroeny@users.noreply.github.com> Date: Thu, 13 Oct 2022 09:23:16 +0200 Subject: [PATCH 15/15] Fix namespace sorting of capitalcase --- src/PhpGenerator/PhpNamespace.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpGenerator/PhpNamespace.php b/src/PhpGenerator/PhpNamespace.php index 660ff026..cf9c005b 100644 --- a/src/PhpGenerator/PhpNamespace.php +++ b/src/PhpGenerator/PhpNamespace.php @@ -162,7 +162,7 @@ public function addUseConstant(string $name, ?string $alias = null): static /** @return string[] */ public function getUses(string $of = self::NameNormal): array { - uasort($this->aliases[$of], fn(string $a, string $b): int => strtr($a, '\\', ' ') <=> strtr($b, '\\', ' ')); + uasort($this->aliases[$of], fn(string $a, string $b): int => strtolower(strtr($a, '\\', ' ')) <=> strtolower(strtr($b, '\\', ' '))); return array_filter( $this->aliases[$of], fn($name, $alias) => strcasecmp(($this->name ? $this->name . '\\' : '') . $alias, $name),