1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Analyser\Generator;
4:
5: use Fiber;
6: use PhpParser\Node;
7: use PhpParser\Node\Expr;
8: use PhpParser\Node\Name;
9: use PhpParser\Node\Param;
10: use PHPStan\Analyser\ExpressionContext;
11: use PHPStan\Analyser\ExpressionTypeHolder;
12: use PHPStan\Analyser\NodeCallbackInvoker;
13: use PHPStan\Analyser\Scope;
14: use PHPStan\Analyser\ScopeContext;
15: use PHPStan\Node\Printer\ExprPrinter;
16: use PHPStan\Php\PhpVersions;
17: use PHPStan\Reflection\ClassConstantReflection;
18: use PHPStan\Reflection\ClassReflection;
19: use PHPStan\Reflection\ExtendedMethodReflection;
20: use PHPStan\Reflection\ExtendedPropertyReflection;
21: use PHPStan\Reflection\MethodReflection;
22: use PHPStan\Reflection\Php\PhpFunctionFromParserNodeReflection;
23: use PHPStan\Reflection\PropertyReflection;
24: use PHPStan\ShouldNotHappenException;
25: use PHPStan\TrinaryLogic;
26: use PHPStan\Type\ClosureType;
27: use PHPStan\Type\Type;
28: use PHPStan\Type\TypeWithClassName;
29: use function array_key_exists;
30:
31: final class GeneratorScope implements Scope, NodeCallbackInvoker
32: {
33:
34: /** @var non-empty-string|null */
35: private ?string $namespace;
36:
37: /**
38: * @param array<string, ExpressionTypeHolder> $expressionTypes
39: * @param array<string, ExpressionTypeHolder> $nativeExpressionTypes
40: */
41: public function __construct(
42: private InternalGeneratorScopeFactory $scopeFactory,
43: private ExprPrinter $exprPrinter,
44: private ScopeContext $context,
45: private bool $declareStrictTypes = false,
46: private PhpFunctionFromParserNodeReflection|null $function = null,
47: ?string $namespace = null,
48: private array $expressionTypes = [],
49: private array $nativeExpressionTypes = [],
50: )
51: {
52: if ($namespace === '') {
53: $namespace = null;
54: }
55:
56: $this->namespace = $namespace;
57: }
58:
59: /**
60: * This method is meant to be called for expressions for which the type
61: * should be stored in Scope itself.
62: *
63: * This is meant to be used only by handlers in PHPStan\Analyser\Generator namespace.
64: *
65: * All other code should use `getType()` method.
66: */
67: public function getExpressionType(Expr $expr): ?Type
68: {
69: $exprString = $this->exprPrinter->printExpr($expr);
70: if (array_key_exists($exprString, $this->expressionTypes)) {
71: return $this->expressionTypes[$exprString]->getType();
72: }
73:
74: return null;
75: }
76:
77: public function assignVariable(string $variableName, Type $type): self
78: {
79: $exprString = '$' . $variableName;
80:
81: $expressionTypes = $this->expressionTypes;
82: $expressionTypes[$exprString] = ExpressionTypeHolder::createYes(new Expr\Variable($variableName), $type);
83:
84: return $this->scopeFactory->create(
85: $this->context,
86: $this->declareStrictTypes,
87: $this->function,
88: $this->namespace,
89: $expressionTypes,
90: );
91: }
92:
93: /** @api */
94: public function enterNamespace(string $namespaceName): self
95: {
96: return $this->scopeFactory->create(
97: $this->context->beginFile(),
98: $this->isDeclareStrictTypes(),
99: null,
100: $namespaceName,
101: );
102: }
103:
104: public function isInClass(): bool
105: {
106: // TODO: Implement isInClass() method.
107: return false;
108: }
109:
110: public function getClassReflection(): ?ClassReflection
111: {
112: // TODO: Implement getClassReflection() method.
113: throw new ShouldNotHappenException('Not implemented yet');
114: }
115:
116: public function canAccessProperty(PropertyReflection $propertyReflection): bool
117: {
118: // TODO: Implement canAccessProperty() method.
119: throw new ShouldNotHappenException('Not implemented yet');
120: }
121:
122: public function canReadProperty(ExtendedPropertyReflection $propertyReflection): bool
123: {
124: // TODO: Implement canReadProperty() method.
125: throw new ShouldNotHappenException('Not implemented yet');
126: }
127:
128: public function canWriteProperty(ExtendedPropertyReflection $propertyReflection): bool
129: {
130: // TODO: Implement canWriteProperty() method.
131: throw new ShouldNotHappenException('Not implemented yet');
132: }
133:
134: public function canCallMethod(MethodReflection $methodReflection): bool
135: {
136: // TODO: Implement canCallMethod() method.
137: return true;
138: }
139:
140: public function canAccessConstant(ClassConstantReflection $constantReflection): bool
141: {
142: // TODO: Implement canAccessConstant() method.
143: throw new ShouldNotHappenException('Not implemented yet');
144: }
145:
146: /** @api */
147: public function getNamespace(): ?string
148: {
149: return $this->namespace;
150: }
151:
152: public function getFile(): string
153: {
154: // TODO: Implement getFile() method.
155: return 'foo.php';
156: }
157:
158: public function getFileDescription(): string
159: {
160: // TODO: Implement getFileDescription() method.
161: return 'foo.php';
162: }
163:
164: /** @api */
165: public function isDeclareStrictTypes(): bool
166: {
167: return $this->declareStrictTypes;
168: }
169:
170: public function enterDeclareStrictTypes(): self
171: {
172: return $this->scopeFactory->create(
173: $this->context,
174: true,
175: null,
176: null,
177: $this->expressionTypes,
178: $this->nativeExpressionTypes,
179: );
180: }
181:
182: public function isInTrait(): bool
183: {
184: // TODO: Implement isInTrait() method.
185: return false;
186: }
187:
188: public function getTraitReflection(): ?ClassReflection
189: {
190: // TODO: Implement getTraitReflection() method.
191: throw new ShouldNotHappenException('Not implemented yet');
192: }
193:
194: public function getFunction(): ?PhpFunctionFromParserNodeReflection
195: {
196: // TODO: Implement getFunction() method.
197: throw new ShouldNotHappenException('Not implemented yet');
198: }
199:
200: public function getFunctionName(): ?string
201: {
202: // TODO: Implement getFunctionName() method.
203: throw new ShouldNotHappenException('Not implemented yet');
204: }
205:
206: public function getParentScope(): ?self
207: {
208: // TODO: Implement getParentScope() method.
209: throw new ShouldNotHappenException('Not implemented yet');
210: }
211:
212: public function hasVariableType(string $variableName): TrinaryLogic
213: {
214: // TODO: Implement hasVariableType() method.
215: throw new ShouldNotHappenException('Not implemented yet');
216: }
217:
218: public function getVariableType(string $variableName): Type
219: {
220: // TODO: Implement getVariableType() method.
221: throw new ShouldNotHappenException('Not implemented yet');
222: }
223:
224: public function canAnyVariableExist(): bool
225: {
226: // TODO: Implement canAnyVariableExist() method.
227: throw new ShouldNotHappenException('Not implemented yet');
228: }
229:
230: public function getDefinedVariables(): array
231: {
232: // TODO: Implement getDefinedVariables() method.
233: throw new ShouldNotHappenException('Not implemented yet');
234: }
235:
236: public function getMaybeDefinedVariables(): array
237: {
238: // TODO: Implement getMaybeDefinedVariables() method.
239: throw new ShouldNotHappenException('Not implemented yet');
240: }
241:
242: public function hasConstant(Name $name): bool
243: {
244: // TODO: Implement hasConstant() method.
245: throw new ShouldNotHappenException('Not implemented yet');
246: }
247:
248: public function getPropertyReflection(Type $typeWithProperty, string $propertyName): ?ExtendedPropertyReflection
249: {
250: // TODO: Implement getPropertyReflection() method.
251: throw new ShouldNotHappenException('Not implemented yet');
252: }
253:
254: public function getInstancePropertyReflection(Type $typeWithProperty, string $propertyName): ?ExtendedPropertyReflection
255: {
256: // TODO: Implement getInstancePropertyReflection() method.
257: throw new ShouldNotHappenException('Not implemented yet');
258: }
259:
260: public function getStaticPropertyReflection(Type $typeWithProperty, string $propertyName): ?ExtendedPropertyReflection
261: {
262: // TODO: Implement getStaticPropertyReflection() method.
263: throw new ShouldNotHappenException('Not implemented yet');
264: }
265:
266: public function getMethodReflection(Type $typeWithMethod, string $methodName): ?ExtendedMethodReflection
267: {
268: // TODO: Implement getMethodReflection() method.
269: return null;
270: }
271:
272: public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ClassConstantReflection
273: {
274: // TODO: Implement getConstantReflection() method.
275: throw new ShouldNotHappenException('Not implemented yet');
276: }
277:
278: public function getConstantExplicitTypeFromConfig(string $constantName, Type $constantType): Type
279: {
280: // TODO: Implement getConstantExplicitTypeFromConfig() method.
281: throw new ShouldNotHappenException('Not implemented yet');
282: }
283:
284: public function getIterableKeyType(Type $iteratee): Type
285: {
286: // TODO: Implement getIterableKeyType() method.
287: throw new ShouldNotHappenException('Not implemented yet');
288: }
289:
290: public function getIterableValueType(Type $iteratee): Type
291: {
292: // TODO: Implement getIterableValueType() method.
293: throw new ShouldNotHappenException('Not implemented yet');
294: }
295:
296: public function isInAnonymousFunction(): bool
297: {
298: // TODO: Implement isInAnonymousFunction() method.
299: throw new ShouldNotHappenException('Not implemented yet');
300: }
301:
302: public function getAnonymousFunctionReflection(): ?ClosureType
303: {
304: // TODO: Implement getAnonymousFunctionReflection() method.
305: throw new ShouldNotHappenException('Not implemented yet');
306: }
307:
308: public function getAnonymousFunctionReturnType(): ?Type
309: {
310: // TODO: Implement getAnonymousFunctionReturnType() method.
311: throw new ShouldNotHappenException('Not implemented yet');
312: }
313:
314: /** @api */
315: public function getType(Expr $node): Type
316: {
317: return Fiber::suspend(new ExprAnalysisRequest(new Node\Stmt\Expression($node), $node, $this, ExpressionContext::createTopLevel()))->type;
318: }
319:
320: public function getNativeType(Expr $expr): Type
321: {
322: // TODO: Implement getNativeType() method.
323: throw new ShouldNotHappenException('Not implemented yet');
324: }
325:
326: public function getKeepVoidType(Expr $node): Type
327: {
328: // TODO: Implement getKeepVoidType() method.
329: throw new ShouldNotHappenException('Not implemented yet');
330: }
331:
332: public function resolveName(Name $name): string
333: {
334: // TODO: Implement resolveName() method.
335: throw new ShouldNotHappenException('Not implemented yet');
336: }
337:
338: public function resolveTypeByName(Name $name): TypeWithClassName
339: {
340: // TODO: Implement resolveTypeByName() method.
341: throw new ShouldNotHappenException('Not implemented yet');
342: }
343:
344: /**
345: * @param mixed $value
346: */
347: public function getTypeFromValue($value): Type
348: {
349: // TODO: Implement getTypeFromValue() method.
350: throw new ShouldNotHappenException('Not implemented yet');
351: }
352:
353: public function hasExpressionType(Expr $node): TrinaryLogic
354: {
355: // TODO: Implement hasExpressionType() method.
356: throw new ShouldNotHappenException('Not implemented yet');
357: }
358:
359: public function isInClassExists(string $className): bool
360: {
361: // TODO: Implement isInClassExists() method.
362: throw new ShouldNotHappenException('Not implemented yet');
363: }
364:
365: public function isInFunctionExists(string $functionName): bool
366: {
367: // TODO: Implement isInFunctionExists() method.
368: throw new ShouldNotHappenException('Not implemented yet');
369: }
370:
371: public function isInClosureBind(): bool
372: {
373: // TODO: Implement isInClosureBind() method.
374: throw new ShouldNotHappenException('Not implemented yet');
375: }
376:
377: public function getFunctionCallStack(): array
378: {
379: // TODO: Implement getFunctionCallStack() method.
380: throw new ShouldNotHappenException('Not implemented yet');
381: }
382:
383: public function getFunctionCallStackWithParameters(): array
384: {
385: // TODO: Implement getFunctionCallStackWithParameters() method.
386: throw new ShouldNotHappenException('Not implemented yet');
387: }
388:
389: public function isParameterValueNullable(Param $parameter): bool
390: {
391: // TODO: Implement isParameterValueNullable() method.
392: throw new ShouldNotHappenException('Not implemented yet');
393: }
394:
395: /**
396: * @param Node\Name|Node\Identifier|Node\ComplexType|null $type
397: */
398: public function getFunctionType($type, bool $isNullable, bool $isVariadic): Type
399: {
400: // TODO: Implement getFunctionType() method.
401: throw new ShouldNotHappenException('Not implemented yet');
402: }
403:
404: public function isInExpressionAssign(Expr $expr): bool
405: {
406: // TODO: Implement isInExpressionAssign() method.
407: throw new ShouldNotHappenException('Not implemented yet');
408: }
409:
410: public function isUndefinedExpressionAllowed(Expr $expr): bool
411: {
412: // TODO: Implement isUndefinedExpressionAllowed() method.
413: throw new ShouldNotHappenException('Not implemented yet');
414: }
415:
416: public function filterByTruthyValue(Expr $expr): Scope
417: {
418: // TODO: Implement filterByTruthyValue() method.
419: throw new ShouldNotHappenException('Not implemented yet');
420: }
421:
422: public function filterByFalseyValue(Expr $expr): Scope
423: {
424: // TODO: Implement filterByFalseyValue() method.
425: throw new ShouldNotHappenException('Not implemented yet');
426: }
427:
428: public function isInFirstLevelStatement(): bool
429: {
430: // TODO: Implement isInFirstLevelStatement() method.
431: throw new ShouldNotHappenException('Not implemented yet');
432: }
433:
434: public function getPhpVersion(): PhpVersions
435: {
436: // TODO: Implement getPhpVersion() method.
437: throw new ShouldNotHappenException('Not implemented yet');
438: }
439:
440: public function invokeNodeCallback(Node $node): void
441: {
442: Fiber::suspend(new NodeCallbackRequest($node, $this));
443: }
444:
445: }
446: