| 1: | <?php declare(strict_types = 1); | 
| 2: |  | 
| 3: | namespace PHPStan\Analyser; | 
| 4: |  | 
| 5: | use PHPStan\Type\Generic\TemplateTypeMap; | 
| 6: | use PHPStan\Type\Generic\TemplateTypeScope; | 
| 7: | use PHPStan\Type\Type; | 
| 8: | use function array_key_exists; | 
| 9: | use function array_merge; | 
| 10: | use function array_shift; | 
| 11: | use function count; | 
| 12: | use function explode; | 
| 13: | use function implode; | 
| 14: | use function ltrim; | 
| 15: | use function sprintf; | 
| 16: | use function str_starts_with; | 
| 17: | use function strtolower; | 
| 18: |  | 
| 19: |  | 
| 20: |  | 
| 21: |  | 
| 22: | final class NameScope | 
| 23: | { | 
| 24: |  | 
| 25: | private TemplateTypeMap $templateTypeMap; | 
| 26: |  | 
| 27: |  | 
| 28: |  | 
| 29: |  | 
| 30: |  | 
| 31: |  | 
| 32: |  | 
| 33: |  | 
| 34: | public function __construct(private ?string $namespace, private array $uses, private ?string $className = null, private ?string $functionName = null, ?TemplateTypeMap $templateTypeMap = null, private array $typeAliasesMap = [], private bool $bypassTypeAliases = false, private array $constUses = [], private ?string $typeAliasClassName = null) | 
| 35: | { | 
| 36: | $this->templateTypeMap = $templateTypeMap ?? TemplateTypeMap::createEmpty(); | 
| 37: | } | 
| 38: |  | 
| 39: | public function getNamespace(): ?string | 
| 40: | { | 
| 41: | return $this->namespace; | 
| 42: | } | 
| 43: |  | 
| 44: |  | 
| 45: |  | 
| 46: |  | 
| 47: | public function getUses(): array | 
| 48: | { | 
| 49: | return $this->uses; | 
| 50: | } | 
| 51: |  | 
| 52: | public function hasUseAlias(string $name): bool | 
| 53: | { | 
| 54: | return isset($this->uses[strtolower($name)]); | 
| 55: | } | 
| 56: |  | 
| 57: |  | 
| 58: |  | 
| 59: |  | 
| 60: | public function getConstUses(): array | 
| 61: | { | 
| 62: | return $this->constUses; | 
| 63: | } | 
| 64: |  | 
| 65: | public function getClassName(): ?string | 
| 66: | { | 
| 67: | return $this->className; | 
| 68: | } | 
| 69: |  | 
| 70: | public function getClassNameForTypeAlias(): ?string | 
| 71: | { | 
| 72: | return $this->typeAliasClassName ?? $this->className; | 
| 73: | } | 
| 74: |  | 
| 75: | public function resolveStringName(string $name): string | 
| 76: | { | 
| 77: | if (str_starts_with($name, '\\')) { | 
| 78: | return ltrim($name, '\\'); | 
| 79: | } | 
| 80: |  | 
| 81: | $nameParts = explode('\\', $name); | 
| 82: | $firstNamePart = strtolower($nameParts[0]); | 
| 83: | if (isset($this->uses[$firstNamePart])) { | 
| 84: | if (count($nameParts) === 1) { | 
| 85: | return $this->uses[$firstNamePart]; | 
| 86: | } | 
| 87: | array_shift($nameParts); | 
| 88: | return sprintf('%s\\%s', $this->uses[$firstNamePart], implode('\\', $nameParts)); | 
| 89: | } | 
| 90: |  | 
| 91: | if ($this->namespace !== null) { | 
| 92: | return sprintf('%s\\%s', $this->namespace, $name); | 
| 93: | } | 
| 94: |  | 
| 95: | return $name; | 
| 96: | } | 
| 97: |  | 
| 98: |  | 
| 99: |  | 
| 100: |  | 
| 101: | public function resolveConstantNames(string $name): array | 
| 102: | { | 
| 103: | if (str_starts_with($name, '\\')) { | 
| 104: | return [ltrim($name, '\\')]; | 
| 105: | } | 
| 106: |  | 
| 107: | $nameParts = explode('\\', $name); | 
| 108: | $firstNamePart = strtolower($nameParts[0]); | 
| 109: |  | 
| 110: | if (count($nameParts) > 1) { | 
| 111: | if (isset($this->uses[$firstNamePart])) { | 
| 112: | array_shift($nameParts); | 
| 113: | return [sprintf('%s\\%s', $this->uses[$firstNamePart], implode('\\', $nameParts))]; | 
| 114: | } | 
| 115: | } elseif (isset($this->constUses[$firstNamePart])) { | 
| 116: | return [$this->constUses[$firstNamePart]]; | 
| 117: | } | 
| 118: |  | 
| 119: | if ($this->namespace !== null) { | 
| 120: | return [ | 
| 121: | sprintf('%s\\%s', $this->namespace, $name), | 
| 122: | $name, | 
| 123: | ]; | 
| 124: | } | 
| 125: |  | 
| 126: | return [$name]; | 
| 127: | } | 
| 128: |  | 
| 129: | public function getTemplateTypeScope(): ?TemplateTypeScope | 
| 130: | { | 
| 131: | if ($this->className !== null) { | 
| 132: | if ($this->functionName !== null) { | 
| 133: | return TemplateTypeScope::createWithMethod($this->className, $this->functionName); | 
| 134: | } | 
| 135: |  | 
| 136: | return TemplateTypeScope::createWithClass($this->className); | 
| 137: | } | 
| 138: |  | 
| 139: | if ($this->functionName !== null) { | 
| 140: | return TemplateTypeScope::createWithFunction($this->functionName); | 
| 141: | } | 
| 142: |  | 
| 143: | return null; | 
| 144: | } | 
| 145: |  | 
| 146: | public function getTemplateTypeMap(): TemplateTypeMap | 
| 147: | { | 
| 148: | return $this->templateTypeMap; | 
| 149: | } | 
| 150: |  | 
| 151: | public function resolveTemplateTypeName(string $name): ?Type | 
| 152: | { | 
| 153: | return $this->templateTypeMap->getType($name); | 
| 154: | } | 
| 155: |  | 
| 156: | public function withTemplateTypeMap(TemplateTypeMap $map): self | 
| 157: | { | 
| 158: | if ($map->isEmpty() && $this->templateTypeMap->isEmpty()) { | 
| 159: | return $this; | 
| 160: | } | 
| 161: |  | 
| 162: | return new self( | 
| 163: | $this->namespace, | 
| 164: | $this->uses, | 
| 165: | $this->className, | 
| 166: | $this->functionName, | 
| 167: | new TemplateTypeMap(array_merge( | 
| 168: | $this->templateTypeMap->getTypes(), | 
| 169: | $map->getTypes(), | 
| 170: | )), | 
| 171: | $this->typeAliasesMap, | 
| 172: | $this->bypassTypeAliases, | 
| 173: | $this->constUses, | 
| 174: | ); | 
| 175: | } | 
| 176: |  | 
| 177: | public function withClassName(string $className): self | 
| 178: | { | 
| 179: | return new self( | 
| 180: | $this->namespace, | 
| 181: | $this->uses, | 
| 182: | $className, | 
| 183: | $this->functionName, | 
| 184: | $this->templateTypeMap, | 
| 185: | $this->typeAliasesMap, | 
| 186: | $this->bypassTypeAliases, | 
| 187: | $this->constUses, | 
| 188: | ); | 
| 189: | } | 
| 190: |  | 
| 191: | public function unsetTemplateType(string $name): self | 
| 192: | { | 
| 193: | $map = $this->templateTypeMap; | 
| 194: | if (!$map->hasType($name)) { | 
| 195: | return $this; | 
| 196: | } | 
| 197: |  | 
| 198: | return new self( | 
| 199: | $this->namespace, | 
| 200: | $this->uses, | 
| 201: | $this->className, | 
| 202: | $this->functionName, | 
| 203: | $this->templateTypeMap->unsetType($name), | 
| 204: | $this->typeAliasesMap, | 
| 205: | $this->bypassTypeAliases, | 
| 206: | $this->constUses, | 
| 207: | ); | 
| 208: | } | 
| 209: |  | 
| 210: | public function bypassTypeAliases(): self | 
| 211: | { | 
| 212: | return new self($this->namespace, $this->uses, $this->className, $this->functionName, $this->templateTypeMap, $this->typeAliasesMap, true, $this->constUses); | 
| 213: | } | 
| 214: |  | 
| 215: | public function shouldBypassTypeAliases(): bool | 
| 216: | { | 
| 217: | return $this->bypassTypeAliases; | 
| 218: | } | 
| 219: |  | 
| 220: | public function hasTypeAlias(string $alias): bool | 
| 221: | { | 
| 222: | return array_key_exists($alias, $this->typeAliasesMap); | 
| 223: | } | 
| 224: |  | 
| 225: | } | 
| 226: |  |