Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/CodeBuilder/Adapter/TolerantParser/TolerantUpdater.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Phpactor\CodeBuilder\Adapter\TolerantParser;

use Microsoft\PhpParser\Node\Expression\ObjectCreationExpression;
use Microsoft\PhpParser\Node\SourceFileNode;
use Microsoft\PhpParser\Node\Statement\ClassDeclaration;
use Microsoft\PhpParser\Node\Statement\TraitDeclaration;
Expand All @@ -22,6 +23,8 @@
use Phpactor\CodeBuilder\Adapter\TolerantParser\Updater\InterfaceUpdater;
use Phpactor\CodeBuilder\Adapter\TolerantParser\Updater\TraitUpdater;
use Phpactor\TextDocument\TextEdits;
use Phpactor\WorseReflection\Core\Util\NodeUtil;
use Microsoft\PhpParser\Token;

class TolerantUpdater implements Updater
{
Expand Down Expand Up @@ -122,6 +125,13 @@ private function updateClasses(Edits $edits, SourceCode $prototype, SourceFileNo
}
}

foreach ($node->getDescendantNodes() as $classNode) {
if ($classNode instanceof ObjectCreationExpression && $classNode->classTypeDesignator instanceof Token) {
$name = NodeUtil::nameFromTokenOrNode($classNode, $classNode);
$classNodes[$name] = $classNode;
}
}

foreach ($prototype->classes()->in(array_keys($classNodes)) as $classPrototype) {
$this->classUpdater->updateClass($edits, $classPrototype, $classNodes[$classPrototype->name()]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\DelimitedList\ParameterDeclarationList;
use Microsoft\PhpParser\Node\EnumCaseDeclaration;
use Microsoft\PhpParser\Node\Expression\ObjectCreationExpression;
use Microsoft\PhpParser\Node\MethodDeclaration;
use Microsoft\PhpParser\Node\Parameter;
use Microsoft\PhpParser\Node\PropertyDeclaration;
Expand All @@ -30,8 +31,11 @@ public function __construct(private Renderer $renderer)
{
}

public function updateMethods(Edits $edits, ClassLikePrototype $classPrototype, ClassLike $classNode): void
{
public function updateMethods(
Edits $edits,
ClassLikePrototype $classPrototype,
ClassLike|ObjectCreationExpression $classNode,
): void {
if (count($classPrototype->methods()) === 0) {
return;
}
Expand Down Expand Up @@ -137,10 +141,10 @@ public function updateMethods(Edits $edits, ClassLikePrototype $classPrototype,
/**
* @return array<Node>
*/
abstract protected function memberDeclarations(ClassLike $classNode): array;
abstract protected function memberDeclarations(ClassLike|ObjectCreationExpression $classNode): array;

/** @return TMembersNodeType */
abstract protected function memberDeclarationsNode(ClassLike $classNode);
abstract protected function memberDeclarationsNode(ClassLike|ObjectCreationExpression $classNode);

abstract protected function renderMethod(Renderer $renderer, Method $method): string;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\ClassConstDeclaration;
use Microsoft\PhpParser\Node\Expression\AssignmentExpression;
use Microsoft\PhpParser\Node\Expression\ObjectCreationExpression;
use Microsoft\PhpParser\Node\Expression\Variable;
use Microsoft\PhpParser\Node\MethodDeclaration;
use Microsoft\PhpParser\Node\PropertyDeclaration;
Expand Down Expand Up @@ -109,11 +110,11 @@ protected function getInsertPlace(Node $classNode, array $memberDeclarations): T
return $insert;
}

/**
* @param ClassDeclaration|TraitDeclaration|EnumDeclaration|InterfaceDeclaration $classLikeDeclaration
*/
protected function updateDocblock(Edits $edits, ClassLikePrototype $classPrototype, $classLikeDeclaration): void
{
protected function updateDocblock(
Edits $edits,
ClassLikePrototype $classPrototype,
ClassDeclaration|TraitDeclaration|EnumDeclaration|InterfaceDeclaration|ObjectCreationExpression $classLikeDeclaration,
): void {
if (!$classPrototype->docblock()->notNone()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Microsoft\PhpParser\Node\ClassMembersNode;
use Microsoft\PhpParser\ClassLike;
use Microsoft\PhpParser\Node\EnumMembers;
use Microsoft\PhpParser\Node\Expression\ObjectCreationExpression;
use Microsoft\PhpParser\Node\InterfaceMembers;
use Microsoft\PhpParser\Node\Statement\ClassDeclaration;
use Microsoft\PhpParser\Node\Statement\EnumDeclaration;
use Microsoft\PhpParser\Node\Statement\TraitDeclaration;
Expand All @@ -13,19 +15,20 @@
use Phpactor\CodeBuilder\Domain\Prototype\Method;
use RuntimeException;
use Microsoft\PhpParser\Node;
use Webmozart\Assert\Assert;

/**
* @extends AbstractMethodUpdater<ClassMembersNode|TraitMembers>
*/
class ClassMethodUpdater extends AbstractMethodUpdater
{
/**
* @return ClassMembersNode|TraitMembers|EnumMembers
*/
public function memberDeclarationsNode(ClassLike $classNode)
public function memberDeclarationsNode(ClassLike|ObjectCreationExpression $classNode): ClassMembersNode|TraitMembers|EnumMembers|InterfaceMembers
{
if ($classNode instanceof ClassDeclaration) {
return $classNode->classMembers;
if ($classNode instanceof ClassDeclaration || $classNode instanceof ObjectCreationExpression) {
$classNode = $classNode->classMembers;
Assert::isInstanceOf($classNode, ClassMembersNode::class);

return $classNode;
}
if ($classNode instanceof TraitDeclaration) {
return $classNode->traitMembers;
Expand All @@ -48,10 +51,10 @@ public function renderMethod(Renderer $renderer, Method $method): string
}

/** @return array<Node> */
protected function memberDeclarations(ClassLike $classNode): array
protected function memberDeclarations(ClassLike|ObjectCreationExpression $classNode): array
{
if ($classNode instanceof ClassDeclaration) {
return $classNode->classMembers->classMemberDeclarations;
if ($classNode instanceof ClassDeclaration || $classNode instanceof ObjectCreationExpression) {
return $classNode->classMembers->classMemberDeclarations ?? [];
}
if ($classNode instanceof TraitDeclaration) {
return $classNode->traitMembers->traitMemberDeclarations;
Expand Down
53 changes: 43 additions & 10 deletions lib/CodeBuilder/Adapter/TolerantParser/Updater/ClassUpdater.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\ClassConstDeclaration;
use Microsoft\PhpParser\Node\ClassMembersNode;
use Microsoft\PhpParser\Node\Expression\ObjectCreationExpression;
use Microsoft\PhpParser\Node\MethodDeclaration;
use Microsoft\PhpParser\Node\PropertyDeclaration;
use Microsoft\PhpParser\Node\Statement\ClassDeclaration;
Expand All @@ -12,20 +14,26 @@
use Phpactor\CodeBuilder\Domain\Prototype\Constant;
use Phpactor\CodeBuilder\Domain\Prototype\ExtendsClass;
use Phpactor\CodeBuilder\Domain\Prototype\ImplementsInterfaces;
use Microsoft\PhpParser\Token;

class ClassUpdater extends ClassLikeUpdater
{
public function updateClass(Edits $edits, ClassPrototype $classPrototype, ClassDeclaration $classNode): void
{
public function updateClass(
Edits $edits,
ClassPrototype $classPrototype,
ClassDeclaration|ObjectCreationExpression $classNode,
): void {
if (false === $classPrototype->applyUpdate()) {
return;
}

$this->updateDocblock($edits, $classPrototype, $classNode);
$this->updateExtends($edits, $classPrototype, $classNode);
$this->updateImplements($edits, $classPrototype, $classNode);
$this->updateConstants($edits, $classPrototype, $classNode->classMembers);
$this->updateProperties($edits, $classPrototype, $classNode->classMembers);
if ($classNode->classMembers instanceof ClassMembersNode) {
$this->updateConstants($edits, $classPrototype, $classNode->classMembers);
$this->updateProperties($edits, $classPrototype, $classNode->classMembers);
}

$this->methodUpdater->updateMethods($edits, $classPrototype, $classNode);
}
Expand Down Expand Up @@ -79,29 +87,41 @@ protected function memberDeclarations(Node $node): array
return $node->classMemberDeclarations;
}

private function updateExtends(Edits $edits, ClassPrototype $classPrototype, ClassDeclaration $classNode): void
{
private function updateExtends(
Edits $edits,
ClassPrototype $classPrototype,
ClassDeclaration|ObjectCreationExpression $classNode,
): void {
if (ExtendsClass::none() == $classPrototype->extendsClass()) {
return;
}

if (null === $classNode->classBaseClause) {
$edits->after($classNode->name, ' extends ' . (string) $classPrototype->extendsClass());
$edits->after(
$this->getTokenBeforeImplementsOrExtends($classNode),
' extends ' . (string) $classPrototype->extendsClass(),
);
return;
}


$edits->replace($classNode->classBaseClause, ' extends ' . (string) $classPrototype->extendsClass());
}

private function updateImplements(Edits $edits, ClassPrototype $classPrototype, ClassDeclaration $classNode): void
{
private function updateImplements(
Edits $edits,
ClassPrototype $classPrototype,
ClassDeclaration|ObjectCreationExpression $classNode,
): void {
if (ImplementsInterfaces::empty() == $classPrototype->implementsInterfaces()) {
return;
}

if (null === $classNode->classInterfaceClause) {
$edits->after($classNode->name, ' implements ' . (string) $classPrototype->implementsInterfaces()->__toString());
$edits->after(
$this->getTokenBeforeImplementsOrExtends($classNode),
' implements ' . (string) $classPrototype->implementsInterfaces(),
);
return;
}

Expand All @@ -121,4 +141,17 @@ private function updateImplements(Edits $edits, ClassPrototype $classPrototype,

$edits->replace($classNode->classInterfaceClause, ' implements ' . $names);
}

private function getTokenBeforeImplementsOrExtends(ObjectCreationExpression|ClassDeclaration $class): Token
{
/** @var Token $token */
$token = match (true) {
// class Test extends SomeClass
$class instanceof ClassDeclaration => $class->name,
// $a = new class () extends SomeClass
$class instanceof ObjectCreationExpression => $class->closeParen,
};

return $token;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
namespace Phpactor\CodeBuilder\Adapter\TolerantParser\Updater;

use Microsoft\PhpParser\ClassLike;
use Microsoft\PhpParser\Node\Expression\ObjectCreationExpression;
use Microsoft\PhpParser\Node\InterfaceMembers;
use Microsoft\PhpParser\Node\Statement\InterfaceDeclaration;
use Phpactor\CodeBuilder\Domain\Renderer;
use Phpactor\CodeBuilder\Domain\Prototype\Method;
use Microsoft\PhpParser\Node;
Expand All @@ -13,12 +15,12 @@
*/
class InterfaceMethodUpdater extends AbstractMethodUpdater
{
/**
* @return InterfaceMembers
*/
public function memberDeclarationsNode(ClassLike $classNode)
public function memberDeclarationsNode(ClassLike|ObjectCreationExpression $classNode): InterfaceMembers
{
return $classNode->interfaceMembers;
if ($classNode instanceof InterfaceDeclaration) {
return $classNode->interfaceMembers;
}
return new InterfaceMembers();
}

public function renderMethod(Renderer $renderer, Method $method): string
Expand All @@ -27,8 +29,8 @@ public function renderMethod(Renderer $renderer, Method $method): string
}

/** @return array<Node> */
protected function memberDeclarations(ClassLike $classNode): array
protected function memberDeclarations(ClassLike|ObjectCreationExpression $classNode): array
{
return $classNode->interfaceMembers->interfaceMemberDeclarations;
return $classNode->interfaceMembers?->interfaceMemberDeclarations ?? [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,35 @@ public function jump(): ?Foo
}
EOT
];

yield 'Implementing in anonymous classes' => [
<<<'EOT'
<?php

interface Animal
{
public function jump(): iterable;
}

$bird = new class() implements Animal {
}
EOT
,
<<<'EOT'
<?php

interface Animal
{
public function jump(): iterable;
}

$bird = new class() implements Animal {
public function jump(): iterable
{
}
}
EOT
];
yield 'It uses "iterable"' => [
<<<'EOT'
<?php
Expand Down
Loading