Skip to content
Merged
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
3 changes: 0 additions & 3 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,5 @@
<ClassMustBeFinal>
<code><![CDATA[NamespaceNodeToContext]]></code>
</ClassMustBeFinal>
<MixedArgumentTypeCoercion>
<code><![CDATA[$this->aliasesToFullyQualifiedNames($namespace)]]></code>
</MixedArgumentTypeCoercion>
</file>
</files>
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 5 additions & 2 deletions src/phpDocumentor/Reflection/Php/Factory/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand All @@ -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;
}
Expand Down
59 changes: 59 additions & 0 deletions src/phpDocumentor/Reflection/Types/BaseToContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use PhpParser\Node;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;

use function array_filter;
use function array_map;
use function array_merge;
use function in_array;

/** @internal */
abstract class BaseToContext
{
/**
* @param GroupUse[]|Use_[] $usages
*
* @return array<string, string>
*/
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),
);
}
}
19 changes: 19 additions & 0 deletions src/phpDocumentor/Reflection/Types/FileToContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace phpDocumentor\Reflection\Types;

use PhpParser\Node;

final class FileToContext extends BaseToContext
{
/** @param Node[] $nodes */
public function __invoke(array $nodes): Context
{
return new Context(
'',
self::flattenUsage(self::filterUsage($nodes)),
);
}
}
46 changes: 2 additions & 44 deletions src/phpDocumentor/Reflection/Types/NamespaceNodeToContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,9 @@

namespace phpDocumentor\Reflection\Types;

use PhpParser\Node;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;

use function array_filter;
use function array_map;
use function array_merge;
use function in_array;

class NamespaceNodeToContext
class NamespaceNodeToContext extends BaseToContext
{
public function __invoke(Namespace_|null $namespace): Context
{
Expand All @@ -25,40 +16,7 @@ public function __invoke(Namespace_|null $namespace): Context

return new Context(
$namespace->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)),
);
}
}
9 changes: 4 additions & 5 deletions tests/integration/EnumTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
);
}
}
33 changes: 33 additions & 0 deletions tests/integration/ProjectCreationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

use Acme\Plugin;

function foo( $output = Plugin::class ) {}

function bar( $output = OBJECT ) {}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down