Skip to content

Centralize property creation. #667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: 6.x
Choose a base branch
from
Draft
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
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ fix-code-style:

.PHONY: static-code-analysis
static-code-analysis: vendor ## Runs a static code analysis with phpstan/phpstan and vimeo/psalm
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/phpstan --configuration=phpstan.neon
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/psalm.phar
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.2-cli vendor/bin/phpstan --configuration=phpstan.neon
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.2-cli vendor/bin/psalm.phar

.PHONY: test
test: test-unit test-functional ## Runs all test suites with phpunit/phpunit
Expand All @@ -25,7 +25,7 @@ test-unit: ## Runs unit tests with phpunit/phpunit

.PHONY: test-functional
test-functional: ## Runs unit tests with phpunit/phpunit
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/phpunit --testsuite=functional
docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:8.1-cli vendor/bin/phpunit --testsuite=integration

.PHONY: dependency-analysis
dependency-analysis: vendor ## Runs a dependency analysis with maglnet/composer-require-checker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ abstract class AbstractFactory implements ProjectFactoryStrategy
{
/** @param iterable<Reducer> $reducers */
public function __construct(
private readonly DocBlockFactoryInterface $docBlockFactory,
protected readonly DocBlockFactoryInterface $docBlockFactory,
protected readonly iterable $reducers = [],
) {
}
Expand Down
68 changes: 16 additions & 52 deletions src/phpDocumentor/Reflection/Php/Factory/ConstructorPromotion.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@
use phpDocumentor\Reflection\DocBlockFactoryInterface;
use phpDocumentor\Reflection\Fqsen;
use phpDocumentor\Reflection\Location;
use phpDocumentor\Reflection\Php\AsyncVisibility;
use phpDocumentor\Reflection\Php\Class_ as ClassElement;
use phpDocumentor\Reflection\Php\Factory\Reducer\Reducer;
use phpDocumentor\Reflection\Php\ProjectFactoryStrategy;
use phpDocumentor\Reflection\Php\Property;
use phpDocumentor\Reflection\Php\StrategyContainer;
use phpDocumentor\Reflection\Php\Visibility;
use PhpParser\Modifiers;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
Expand Down Expand Up @@ -67,17 +64,22 @@ private function promoteParameterToProperty(ContextStack $context, StrategyConta
Assert::isInstanceOf($methodContainer, ClassElement::class);
Assert::isInstanceOf($param->var, Variable::class);

$property = new Property(
new Fqsen($methodContainer->getFqsen() . '::$' . (string) $param->var->name),
$this->buildPropertyVisibilty($param->flags),
$this->createDocBlock($param->getDocComment(), $context->getTypeContext()),
$param->default !== null ? $this->valueConverter->prettyPrintExpr($param->default) : null,
false,
new Location($param->getLine()),
new Location($param->getEndLine()),
(new Type())->fromPhpParser($param->type),
$this->readOnly($param->flags),
);
$property = PropertyBuilder::create(
$this->valueConverter,
$this->docBlockFactory,
$strategies,
$this->reducers,
)->fqsen(new Fqsen($methodContainer->getFqsen() . '::$' . (string) $param->var->name))
->visibility($param)
->type($param->type)
->docblock($param->getDocComment())
->default($param->default)
->readOnly($this->readOnly($param->flags))
->static(false)
->startLocation(new Location($param->getLine(), $param->getStartFilePos()))
->endLocation(new Location($param->getEndLine(), $param->getEndFilePos()))
->hooks($param->hooks ?? [])
->build($context);

foreach ($this->reducers as $reducer) {
$property = $reducer->reduce($context, $param, $strategies, $property);
Expand All @@ -90,44 +92,6 @@ private function promoteParameterToProperty(ContextStack $context, StrategyConta
$methodContainer->addProperty($property);
}

private function buildPropertyVisibilty(int $flags): Visibility
{
if ((bool) ($flags & Modifiers::VISIBILITY_SET_MASK) !== false) {
return new AsyncVisibility(
$this->buildReadVisibility($flags),
$this->buildWriteVisibility($flags),
);
}

return $this->buildReadVisibility($flags);
}

private function buildReadVisibility(int $flags): Visibility
{
if ((bool) ($flags & Modifiers::PRIVATE) === true) {
return new Visibility(Visibility::PRIVATE_);
}

if ((bool) ($flags & Modifiers::PROTECTED) === true) {
return new Visibility(Visibility::PROTECTED_);
}

return new Visibility(Visibility::PUBLIC_);
}

private function buildWriteVisibility(int $flags): Visibility
{
if ((bool) ($flags & Modifiers::PRIVATE_SET) === true) {
return new Visibility(Visibility::PRIVATE_);
}

if ((bool) ($flags & Modifiers::PROTECTED_SET) === true) {
return new Visibility(Visibility::PROTECTED_);
}

return new Visibility(Visibility::PUBLIC_);
}

private function readOnly(int $flags): bool
{
return (bool) ($flags & Modifiers::READONLY) === true;
Expand Down
11 changes: 6 additions & 5 deletions src/phpDocumentor/Reflection/Php/Factory/ContextStack.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@
use phpDocumentor\Reflection\Element;
use phpDocumentor\Reflection\Php\File as FileElement;
use phpDocumentor\Reflection\Php\Project;
use phpDocumentor\Reflection\Php\PropertyHook;
use phpDocumentor\Reflection\Types\Context as TypeContext;

use function array_reverse;
use function end;

final class ContextStack
{
/** @var (Element|FileElement)[] */
/** @var (Element|FileElement|PropertyHook)[] */
private array $elements = [];

public function __construct(private readonly Project $project, private readonly TypeContext|null $typeContext = null)
{
}

/** @param (Element|FileElement)[] $elements */
/** @param (Element|FileElement|PropertyHook)[] $elements */
private static function createFromSelf(Project $project, TypeContext|null $typeContext, array $elements): self
{
$self = new self($project, $typeContext);
Expand All @@ -31,7 +32,7 @@ private static function createFromSelf(Project $project, TypeContext|null $typeC
return $self;
}

public function push(Element|FileElement $element): self
public function push(Element|FileElement|PropertyHook $element): self
{
$elements = $this->elements;
$elements[] = $element;
Expand All @@ -54,7 +55,7 @@ public function getProject(): Project
return $this->project;
}

public function peek(): Element|FileElement
public function peek(): Element|FileElement|PropertyHook
{
$element = end($this->elements);
if ($element === false) {
Expand All @@ -72,7 +73,7 @@ public function peek(): Element|FileElement
*
* @param class-string $type
*/
public function search(string $type): Element|FileElement|null
public function search(string $type): Element|FileElement|PropertyHook|null
{
$reverseElements = array_reverse($this->elements);
foreach ($reverseElements as $element) {
Expand Down
79 changes: 17 additions & 62 deletions src/phpDocumentor/Reflection/Php/Factory/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@

use phpDocumentor\Reflection\DocBlockFactoryInterface;
use phpDocumentor\Reflection\Location;
use phpDocumentor\Reflection\Php\AsyncVisibility;
use phpDocumentor\Reflection\Php\Class_;
use phpDocumentor\Reflection\Php\Factory\Reducer\Reducer;
use phpDocumentor\Reflection\Php\Property as PropertyDescriptor;
use phpDocumentor\Reflection\Php\StrategyContainer;
use phpDocumentor\Reflection\Php\Trait_;
use phpDocumentor\Reflection\Php\Visibility;
use PhpParser\Node\Stmt\Property as PropertyNode;
use PhpParser\PrettyPrinter\Standard as PrettyPrinter;
use Webmozart\Assert\Assert;
Expand Down Expand Up @@ -73,22 +71,23 @@ protected function doCreate(

$iterator = new PropertyIterator($object);
foreach ($iterator as $stmt) {
$default = $iterator->getDefault();
if ($default !== null) {
$default = $this->valueConverter->prettyPrintExpr($default);
}

$property = new PropertyDescriptor(
$stmt->getFqsen(),
$this->buildVisibility($stmt),
$this->createDocBlock($stmt->getDocComment(), $context->getTypeContext()),
$default,
$stmt->isStatic(),
new Location($stmt->getLine()),
new Location($stmt->getEndLine()),
(new Type())->fromPhpParser($stmt->getType()),
$stmt->isReadonly(),
);
$property = PropertyBuilder::create(
$this->valueConverter,
$this->docBlockFactory,
$strategies,
$this->reducers,
)
->fqsen($stmt->getFqsen())
->visibility($stmt)
->type($stmt->getType())
->docblock($stmt->getDocComment())
->default($iterator->getDefault())
->static($stmt->isStatic())
->startLocation(new Location($stmt->getLine()))
->endLocation(new Location($stmt->getEndLine()))
->readOnly($stmt->isReadonly())
->hooks($stmt->getHooks())
->build($context);

foreach ($this->reducers as $reducer) {
$property = $reducer->reduce($context, $object, $strategies, $property);
Expand All @@ -103,48 +102,4 @@ protected function doCreate(

return null;
}

/**
* Converts the visibility of the property to a valid Visibility object.
*/
private function buildVisibility(PropertyIterator $node): Visibility
{
if ($node->isAsync() === false) {
return $this->buildReadVisibility($node);
}

$readVisibility = $this->buildReadVisibility($node);
$writeVisibility = $this->buildWriteVisibility($node);

return new AsyncVisibility(
$readVisibility,
$writeVisibility,
);
}

private function buildReadVisibility(PropertyIterator $node): Visibility
{
if ($node->isPrivate()) {
return new Visibility(Visibility::PRIVATE_);
}

if ($node->isProtected()) {
return new Visibility(Visibility::PROTECTED_);
}

return new Visibility(Visibility::PUBLIC_);
}

private function buildWriteVisibility(PropertyIterator $node): Visibility
{
if ($node->isPrivateSet()) {
return new Visibility(Visibility::PRIVATE_);
}

if ($node->isProtectedSet()) {
return new Visibility(Visibility::PROTECTED_);
}

return new Visibility(Visibility::PUBLIC_);
}
}
Loading
Loading