1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Type\Accessory;
4:
5: use PHPStan\TrinaryLogic;
6: use PHPStan\Type\CompoundType;
7: use PHPStan\Type\Constant\ConstantArrayType;
8: use PHPStan\Type\Constant\ConstantIntegerType;
9: use PHPStan\Type\Constant\ConstantStringType;
10: use PHPStan\Type\ErrorType;
11: use PHPStan\Type\FloatType;
12: use PHPStan\Type\GeneralizePrecision;
13: use PHPStan\Type\IntegerType;
14: use PHPStan\Type\IntersectionType;
15: use PHPStan\Type\StringType;
16: use PHPStan\Type\Traits\MaybeCallableTypeTrait;
17: use PHPStan\Type\Traits\NonArrayTypeTrait;
18: use PHPStan\Type\Traits\NonGenericTypeTrait;
19: use PHPStan\Type\Traits\NonIterableTypeTrait;
20: use PHPStan\Type\Traits\NonObjectTypeTrait;
21: use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;
22: use PHPStan\Type\Traits\UndecidedComparisonCompoundTypeTrait;
23: use PHPStan\Type\Type;
24: use PHPStan\Type\TypeCombinator;
25: use PHPStan\Type\UnionType;
26: use PHPStan\Type\VerbosityLevel;
27:
28: class AccessoryNonEmptyStringType implements CompoundType, AccessoryType
29: {
30:
31: use MaybeCallableTypeTrait;
32: use NonArrayTypeTrait;
33: use NonObjectTypeTrait;
34: use NonIterableTypeTrait;
35: use UndecidedComparisonCompoundTypeTrait;
36: use NonGenericTypeTrait;
37: use UndecidedBooleanTypeTrait;
38:
39: /** @api */
40: public function __construct()
41: {
42: }
43:
44: public function getReferencedClasses(): array
45: {
46: return [];
47: }
48:
49: public function getConstantStrings(): array
50: {
51: return [];
52: }
53:
54: public function accepts(Type $type, bool $strictTypes): TrinaryLogic
55: {
56: if ($type instanceof CompoundType) {
57: return $type->isAcceptedBy($this, $strictTypes);
58: }
59:
60: return $type->isNonEmptyString();
61: }
62:
63: public function isSuperTypeOf(Type $type): TrinaryLogic
64: {
65: if ($type instanceof CompoundType) {
66: return $type->isSubTypeOf($this);
67: }
68:
69: if ($this->equals($type)) {
70: return TrinaryLogic::createYes();
71: }
72:
73: if ($type->isNonFalsyString()->yes()) {
74: return TrinaryLogic::createYes();
75: }
76:
77: return $type->isNonEmptyString();
78: }
79:
80: public function isSubTypeOf(Type $otherType): TrinaryLogic
81: {
82: if ($otherType instanceof UnionType || $otherType instanceof IntersectionType) {
83: return $otherType->isSuperTypeOf($this);
84: }
85:
86: return $otherType->isNonEmptyString()
87: ->and($otherType instanceof self ? TrinaryLogic::createYes() : TrinaryLogic::createMaybe());
88: }
89:
90: public function isAcceptedBy(Type $acceptingType, bool $strictTypes): TrinaryLogic
91: {
92: return $this->isSubTypeOf($acceptingType);
93: }
94:
95: public function equals(Type $type): bool
96: {
97: return $type instanceof self;
98: }
99:
100: public function describe(VerbosityLevel $level): string
101: {
102: return 'non-empty-string';
103: }
104:
105: public function isOffsetAccessible(): TrinaryLogic
106: {
107: return TrinaryLogic::createYes();
108: }
109:
110: public function hasOffsetValueType(Type $offsetType): TrinaryLogic
111: {
112: return (new IntegerType())->isSuperTypeOf($offsetType)->and(TrinaryLogic::createMaybe());
113: }
114:
115: public function getOffsetValueType(Type $offsetType): Type
116: {
117: if ($this->hasOffsetValueType($offsetType)->no()) {
118: return new ErrorType();
119: }
120:
121: if ((new ConstantIntegerType(0))->isSuperTypeOf($offsetType)->yes()) {
122: return new IntersectionType([new StringType(), new AccessoryNonEmptyStringType()]);
123: }
124:
125: return new StringType();
126: }
127:
128: public function setOffsetValueType(?Type $offsetType, Type $valueType, bool $unionValues = true): Type
129: {
130: return $this;
131: }
132:
133: public function unsetOffset(Type $offsetType): Type
134: {
135: return new ErrorType();
136: }
137:
138: public function toNumber(): Type
139: {
140: return new ErrorType();
141: }
142:
143: public function toInteger(): Type
144: {
145: return new IntegerType();
146: }
147:
148: public function toFloat(): Type
149: {
150: return new FloatType();
151: }
152:
153: public function toString(): Type
154: {
155: return $this;
156: }
157:
158: public function toArray(): Type
159: {
160: return new ConstantArrayType(
161: [new ConstantIntegerType(0)],
162: [$this],
163: [1],
164: [],
165: true,
166: );
167: }
168:
169: public function toArrayKey(): Type
170: {
171: return $this;
172: }
173:
174: public function isNull(): TrinaryLogic
175: {
176: return TrinaryLogic::createNo();
177: }
178:
179: public function isTrue(): TrinaryLogic
180: {
181: return TrinaryLogic::createNo();
182: }
183:
184: public function isFalse(): TrinaryLogic
185: {
186: return TrinaryLogic::createNo();
187: }
188:
189: public function isBoolean(): TrinaryLogic
190: {
191: return TrinaryLogic::createNo();
192: }
193:
194: public function isFloat(): TrinaryLogic
195: {
196: return TrinaryLogic::createNo();
197: }
198:
199: public function isInteger(): TrinaryLogic
200: {
201: return TrinaryLogic::createNo();
202: }
203:
204: public function isString(): TrinaryLogic
205: {
206: return TrinaryLogic::createYes();
207: }
208:
209: public function isNumericString(): TrinaryLogic
210: {
211: return TrinaryLogic::createMaybe();
212: }
213:
214: public function isNonEmptyString(): TrinaryLogic
215: {
216: return TrinaryLogic::createYes();
217: }
218:
219: public function isNonFalsyString(): TrinaryLogic
220: {
221: return TrinaryLogic::createMaybe();
222: }
223:
224: public function isLiteralString(): TrinaryLogic
225: {
226: return TrinaryLogic::createMaybe();
227: }
228:
229: public function isClassStringType(): TrinaryLogic
230: {
231: return TrinaryLogic::createMaybe();
232: }
233:
234: public function isVoid(): TrinaryLogic
235: {
236: return TrinaryLogic::createNo();
237: }
238:
239: public function isScalar(): TrinaryLogic
240: {
241: return TrinaryLogic::createYes();
242: }
243:
244: public function traverse(callable $cb): Type
245: {
246: return $this;
247: }
248:
249: public function generalize(GeneralizePrecision $precision): Type
250: {
251: return new StringType();
252: }
253:
254: public static function __set_state(array $properties): Type
255: {
256: return new self();
257: }
258:
259: public function tryRemove(Type $typeToRemove): ?Type
260: {
261: if ($typeToRemove instanceof ConstantStringType && $typeToRemove->getValue() === '0') {
262: return TypeCombinator::intersect($this, new AccessoryNonFalsyStringType());
263: }
264:
265: return null;
266: }
267:
268: }
269: