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
30 changes: 30 additions & 0 deletions src/Node/ClassConstant.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare(strict_types = 1);

namespace PHPStan\Node;

use PhpParser\Node\Stmt\ClassConst;

/**
* @api
*/
final class ClassConstant
{

public function __construct(
private ClassConst $node,
private bool $isDeclaredInTrait,
)
{
}

public function getNode(): ClassConst
{
return $this->node;
}

public function isDeclaredInTrait(): bool
{
return $this->isDeclaredInTrait;
}

}
11 changes: 10 additions & 1 deletion src/Node/ClassConstantsNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\NodeAbstract;
use PHPStan\Node\Constant\ClassConstantFetch;
use PHPStan\Reflection\ClassReflection;
use function array_map;

/**
* @api
Expand All @@ -16,7 +17,7 @@ final class ClassConstantsNode extends NodeAbstract implements VirtualNode
{

/**
* @param ClassConst[] $constants
* @param ClassConstant[] $constants
* @param ClassConstantFetch[] $fetches
*/
public function __construct(private ClassLike $class, private array $constants, private array $fetches, private ClassReflection $classReflection)
Expand All @@ -33,6 +34,14 @@ public function getClass(): ClassLike
* @return ClassConst[]
*/
public function getConstants(): array
{
return array_map(static fn (ClassConstant $constant) => $constant->getNode(), $this->constants);
}

/**
* @return ClassConstant[]
*/
public function getClassConstants(): array
{
return $this->constants;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Node/ClassStatementsGatherer.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ final class ClassStatementsGatherer
/** @var array<int, PropertyWrite|PropertyRead> */
private array $propertyUsages = [];

/** @var Node\Stmt\ClassConst[] */
/** @var ClassConstant[] */
private array $constants = [];

/** @var ClassConstantFetch[] */
Expand Down Expand Up @@ -103,7 +103,7 @@ public function getPropertyUsages(): array
}

/**
* @return Node\Stmt\ClassConst[]
* @return ClassConstant[]
*/
public function getConstants(): array
{
Expand Down Expand Up @@ -165,7 +165,7 @@ private function gatherNodes(Node $node, Scope $scope): void
return;
}
if ($node instanceof Node\Stmt\ClassConst) {
$this->constants[] = $node;
$this->constants[] = new ClassConstant($node, $scope->isInTrait());
return;
}
if ($node instanceof MethodCall || $node instanceof StaticCall) {
Expand Down
7 changes: 6 additions & 1 deletion src/Rules/DeadCode/UnusedPrivateConstantRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,16 @@ public function processNode(Node $node, Scope $scope): array
$classType = new ObjectType($classReflection->getName(), classReflection: $classReflection);

$constants = [];
foreach ($node->getConstants() as $constant) {
foreach ($node->getClassConstants() as $classConstant) {
$constant = $classConstant->getNode();
if (!$constant->isPrivate()) {
continue;
}

if ($classConstant->isDeclaredInTrait()) {
continue;
}

foreach ($constant->consts as $const) {
$constantName = $const->name->toString();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ public function testBug9765(): void
$this->analyse([__DIR__ . '/data/bug-9765.php'], []);
}

#[RequiresPhp('>= 8.2')]
public function testBug10690(): void
{
$this->analyse([__DIR__ . '/data/bug-10690.php'], []);
}

#[RequiresPhp('>= 8.3')]
public function testDynamicConstantFetch(): void
{
Expand Down
29 changes: 29 additions & 0 deletions tests/PHPStan/Rules/DeadCode/data/bug-10690.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php // lint >= 8.2

declare(strict_types = 1);

namespace Bug10690;

trait MyTrait
{
private const AAA='aaa';
private const BBB='bbb';
}

final class First
{
use MyTrait;

function a(): string {
return self::AAA.self::BBB;
}
}

final class SecondConsumer
{
use MyTrait;

function b(): string {
return self::AAA;
}
}
Loading