Skip to content

Commit 4b1ad5d

Browse files
committed
Introduce getUnresolvedPropertyPrototype to Type interface
1 parent 8427203 commit 4b1ad5d

21 files changed

+797
-69
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Type;
4+
5+
use PHPStan\Reflection\ClassReflection;
6+
use PHPStan\Reflection\Dummy\ChangedTypePropertyReflection;
7+
use PHPStan\Reflection\PropertyReflection;
8+
use PHPStan\Reflection\ResolvedPropertyReflection;
9+
use PHPStan\Type\Type;
10+
11+
class CallbackUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection
12+
{
13+
14+
private PropertyReflection $propertyReflection;
15+
16+
private ClassReflection $resolvedDeclaringClass;
17+
18+
private bool $resolveTemplateTypeMapToBounds;
19+
20+
/** @var callable(Type): Type */
21+
private $transformStaticTypeCallback;
22+
23+
/**
24+
* @param PropertyReflection $propertyReflection
25+
* @param ClassReflection $resolvedDeclaringClass
26+
* @param bool $resolveTemplateTypeMapToBounds
27+
* @param callable(Type): Type $transformStaticTypeCallback
28+
*/
29+
public function __construct(
30+
PropertyReflection $propertyReflection,
31+
ClassReflection $resolvedDeclaringClass,
32+
bool $resolveTemplateTypeMapToBounds,
33+
callable $transformStaticTypeCallback
34+
)
35+
{
36+
$this->propertyReflection = $propertyReflection;
37+
$this->resolvedDeclaringClass = $resolvedDeclaringClass;
38+
$this->resolveTemplateTypeMapToBounds = $resolveTemplateTypeMapToBounds;
39+
$this->transformStaticTypeCallback = $transformStaticTypeCallback;
40+
}
41+
42+
public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection
43+
{
44+
return new self(
45+
$this->propertyReflection,
46+
$this->resolvedDeclaringClass,
47+
false,
48+
$this->transformStaticTypeCallback
49+
);
50+
}
51+
52+
public function getNakedProperty(): PropertyReflection
53+
{
54+
return $this->propertyReflection;
55+
}
56+
57+
public function getTransformedProperty(): PropertyReflection
58+
{
59+
$templateTypeMap = $this->resolvedDeclaringClass->getActiveTemplateTypeMap();
60+
61+
return new ResolvedPropertyReflection(
62+
$this->transformPropertyWithStaticType($this->resolvedDeclaringClass, $this->propertyReflection),
63+
$this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap
64+
);
65+
}
66+
67+
public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection
68+
{
69+
return new CalledOnTypeUnresolvedPropertyPrototypeReflection(
70+
$this->propertyReflection,
71+
$this->resolvedDeclaringClass,
72+
$this->resolveTemplateTypeMapToBounds,
73+
$type
74+
);
75+
}
76+
77+
protected function transformPropertyWithStaticType(ClassReflection $declaringClass, PropertyReflection $property): PropertyReflection
78+
{
79+
$readableType = $this->transformStaticType($property->getReadableType());
80+
$writableType = $this->transformStaticType($property->getWritableType());
81+
82+
return new ChangedTypePropertyReflection($declaringClass, $property, $readableType, $writableType);
83+
}
84+
85+
private function transformStaticType(Type $type): Type
86+
{
87+
$callback = $this->transformStaticTypeCallback;
88+
return $callback($type);
89+
}
90+
91+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Type;
4+
5+
use PHPStan\Reflection\ClassReflection;
6+
use PHPStan\Reflection\Dummy\ChangedTypePropertyReflection;
7+
use PHPStan\Reflection\PropertyReflection;
8+
use PHPStan\Reflection\ResolvedPropertyReflection;
9+
use PHPStan\Type\StaticType;
10+
use PHPStan\Type\Type;
11+
use PHPStan\Type\TypeTraverser;
12+
13+
class CalledOnTypeUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection
14+
{
15+
16+
private PropertyReflection $propertyReflection;
17+
18+
private ClassReflection $resolvedDeclaringClass;
19+
20+
private bool $resolveTemplateTypeMapToBounds;
21+
22+
private Type $fetchedOnType;
23+
24+
public function __construct(
25+
PropertyReflection $propertyReflection,
26+
ClassReflection $resolvedDeclaringClass,
27+
bool $resolveTemplateTypeMapToBounds,
28+
Type $fetchedOnType
29+
)
30+
{
31+
$this->propertyReflection = $propertyReflection;
32+
$this->resolvedDeclaringClass = $resolvedDeclaringClass;
33+
$this->resolveTemplateTypeMapToBounds = $resolveTemplateTypeMapToBounds;
34+
$this->fetchedOnType = $fetchedOnType;
35+
}
36+
37+
public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection
38+
{
39+
return new self(
40+
$this->propertyReflection,
41+
$this->resolvedDeclaringClass,
42+
false,
43+
$this->fetchedOnType
44+
);
45+
}
46+
47+
public function getNakedProperty(): PropertyReflection
48+
{
49+
return $this->propertyReflection;
50+
}
51+
52+
public function getTransformedProperty(): PropertyReflection
53+
{
54+
$templateTypeMap = $this->resolvedDeclaringClass->getActiveTemplateTypeMap();
55+
56+
return new ResolvedPropertyReflection(
57+
$this->transformPropertyWithStaticType($this->resolvedDeclaringClass, $this->propertyReflection),
58+
$this->resolveTemplateTypeMapToBounds ? $templateTypeMap->resolveToBounds() : $templateTypeMap
59+
);
60+
}
61+
62+
public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection
63+
{
64+
return new self(
65+
$this->propertyReflection,
66+
$this->resolvedDeclaringClass,
67+
$this->resolveTemplateTypeMapToBounds,
68+
$type
69+
);
70+
}
71+
72+
protected function transformPropertyWithStaticType(ClassReflection $declaringClass, PropertyReflection $property): PropertyReflection
73+
{
74+
$readableType = $this->transformStaticType($property->getReadableType());
75+
$writableType = $this->transformStaticType($property->getWritableType());
76+
77+
return new ChangedTypePropertyReflection($declaringClass, $property, $readableType, $writableType);
78+
}
79+
80+
private function transformStaticType(Type $type): Type
81+
{
82+
return TypeTraverser::map($type, function (Type $type, callable $traverse): Type {
83+
if ($type instanceof StaticType) {
84+
return $this->fetchedOnType;
85+
}
86+
87+
return $traverse($type);
88+
});
89+
}
90+
91+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Type;
4+
5+
use PHPStan\Reflection\ClassReflection;
6+
use PHPStan\Reflection\PropertyReflection;
7+
use PHPStan\TrinaryLogic;
8+
use PHPStan\Type\Type;
9+
use PHPStan\Type\TypeCombinator;
10+
11+
class IntersectionTypePropertyReflection implements PropertyReflection
12+
{
13+
14+
/** @var PropertyReflection[] */
15+
private array $properties;
16+
17+
/**
18+
* @param \PHPStan\Reflection\PropertyReflection[] $properties
19+
*/
20+
public function __construct(array $properties)
21+
{
22+
$this->properties = $properties;
23+
}
24+
25+
public function getDeclaringClass(): ClassReflection
26+
{
27+
return $this->properties[0]->getDeclaringClass();
28+
}
29+
30+
public function isStatic(): bool
31+
{
32+
foreach ($this->properties as $property) {
33+
if ($property->isStatic()) {
34+
return true;
35+
}
36+
}
37+
38+
return false;
39+
}
40+
41+
public function isPrivate(): bool
42+
{
43+
foreach ($this->properties as $property) {
44+
if (!$property->isPrivate()) {
45+
return false;
46+
}
47+
}
48+
49+
return true;
50+
}
51+
52+
public function isPublic(): bool
53+
{
54+
foreach ($this->properties as $property) {
55+
if ($property->isPublic()) {
56+
return true;
57+
}
58+
}
59+
60+
return false;
61+
}
62+
63+
public function isDeprecated(): TrinaryLogic
64+
{
65+
return TrinaryLogic::maxMin(...array_map(static function (PropertyReflection $property): TrinaryLogic {
66+
return $property->isDeprecated();
67+
}, $this->properties));
68+
}
69+
70+
public function getDeprecatedDescription(): ?string
71+
{
72+
$descriptions = [];
73+
foreach ($this->properties as $property) {
74+
if (!$property->isDeprecated()->yes()) {
75+
continue;
76+
}
77+
$description = $property->getDeprecatedDescription();
78+
if ($description === null) {
79+
continue;
80+
}
81+
82+
$descriptions[] = $description;
83+
}
84+
85+
if (count($descriptions) === 0) {
86+
return null;
87+
}
88+
89+
return implode(' ', $descriptions);
90+
}
91+
92+
public function isInternal(): TrinaryLogic
93+
{
94+
return TrinaryLogic::maxMin(...array_map(static function (PropertyReflection $property): TrinaryLogic {
95+
return $property->isInternal();
96+
}, $this->properties));
97+
}
98+
99+
public function getDocComment(): ?string
100+
{
101+
return null;
102+
}
103+
104+
public function getReadableType(): Type
105+
{
106+
return TypeCombinator::intersect(...array_map(static function (PropertyReflection $property): Type {
107+
return $property->getReadableType();
108+
}, $this->properties));
109+
}
110+
111+
public function getWritableType(): Type
112+
{
113+
return TypeCombinator::intersect(...array_map(static function (PropertyReflection $property): Type {
114+
return $property->getWritableType();
115+
}, $this->properties));
116+
}
117+
118+
public function canChangeTypeAfterAssignment(): bool
119+
{
120+
foreach ($this->properties as $property) {
121+
if (!$property->canChangeTypeAfterAssignment()) {
122+
return false;
123+
}
124+
}
125+
126+
return true;
127+
}
128+
129+
public function isReadable(): bool
130+
{
131+
foreach ($this->properties as $property) {
132+
if (!$property->isReadable()) {
133+
return false;
134+
}
135+
}
136+
137+
return true;
138+
}
139+
140+
public function isWritable(): bool
141+
{
142+
foreach ($this->properties as $property) {
143+
if (!$property->isWritable()) {
144+
return false;
145+
}
146+
}
147+
148+
return true;
149+
}
150+
151+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Type;
4+
5+
use PHPStan\Reflection\PropertyReflection;
6+
use PHPStan\Type\Type;
7+
8+
class IntersectionTypeUnresolvedPropertyPrototypeReflection implements UnresolvedPropertyPrototypeReflection
9+
{
10+
11+
private string $propertyName;
12+
13+
/** @var UnresolvedPropertyPrototypeReflection[] */
14+
private array $propertyPrototypes;
15+
16+
/**
17+
* @param UnresolvedPropertyPrototypeReflection[] $propertyPrototypes
18+
*/
19+
public function __construct(
20+
string $propertyName,
21+
array $propertyPrototypes
22+
)
23+
{
24+
$this->propertyName = $propertyName;
25+
$this->propertyPrototypes = $propertyPrototypes;
26+
}
27+
28+
public function doNotResolveTemplateTypeMapToBounds(): UnresolvedPropertyPrototypeReflection
29+
{
30+
return new self($this->propertyName, array_map(static function (UnresolvedPropertyPrototypeReflection $prototype): UnresolvedPropertyPrototypeReflection {
31+
return $prototype->doNotResolveTemplateTypeMapToBounds();
32+
}, $this->propertyPrototypes));
33+
}
34+
35+
public function getNakedProperty(): PropertyReflection
36+
{
37+
return $this->getTransformedProperty();
38+
}
39+
40+
public function getTransformedProperty(): PropertyReflection
41+
{
42+
$properties = array_map(static function (UnresolvedPropertyPrototypeReflection $prototype): PropertyReflection {
43+
return $prototype->getTransformedProperty();
44+
}, $this->propertyPrototypes);
45+
46+
return new IntersectionTypePropertyReflection($properties);
47+
}
48+
49+
public function withFechedOnType(Type $type): UnresolvedPropertyPrototypeReflection
50+
{
51+
return new self($this->propertyName, array_map(static function (UnresolvedPropertyPrototypeReflection $prototype) use ($type): UnresolvedPropertyPrototypeReflection {
52+
return $prototype->withFechedOnType($type);
53+
}, $this->propertyPrototypes));
54+
}
55+
56+
}

0 commit comments

Comments
 (0)