PHPStan\Type\FileTypeMapper::createTypeMap PHP Method

createTypeMap() private method

private createTypeMap ( string $fileName ) : array
$fileName string
return array
    private function createTypeMap(string $fileName) : array
    {
        $objectTypes = [];
        $typeMap = [];
        $processTypeString = function (string $typeString, string $className = null) use(&$typeMap, &$objectTypes) {
            if (isset($typeMap[$typeString])) {
                return;
            }
            $type = $this->getTypeFromTypeString($typeString, $className);
            if ($type instanceof ArrayType) {
                $nestedItemType = $type->getNestedItemType();
                if ($nestedItemType->getItemType() instanceof ObjectType) {
                    if ($nestedItemType->getItemType()->getClass() === $className) {
                        $typeMap[$typeString] = ArrayType::createDeepArrayType(new NestedArrayItemType(new ObjectType($className, false), $nestedItemType->getDepth()), $type->isNullable());
                    } else {
                        $objectTypes[] = ['type' => $nestedItemType->getItemType(), 'typeString' => $typeString, 'arrayType' => ['depth' => $nestedItemType->getDepth(), 'nullable' => $type->isNullable()]];
                    }
                } else {
                    $typeMap[$typeString] = $type;
                }
                return;
            }
            if (!$type instanceof ObjectType) {
                $typeMap[$typeString] = $type;
                return;
            } elseif ($type->getClass() === $className) {
                $typeMap[$typeString] = $type;
                return;
            }
            $objectTypes[] = ['type' => $type, 'typeString' => $typeString];
        };
        $patterns = ['#@param\\s+' . self::TYPE_PATTERN . '\\s+\\$[a-zA-Z0-9_]+#', '#@var\\s+' . self::TYPE_PATTERN . '#', '#@var\\s+\\$[a-zA-Z0-9_]+\\s+' . self::TYPE_PATTERN . '#', '#@return\\s+' . self::TYPE_PATTERN . '#'];
        /** @var \PhpParser\Node\Stmt\ClassLike|null $lastClass */
        $lastClass = null;
        $this->processNodes($this->parser->parseFile($fileName), function (\PhpParser\Node $node, string $className = null) use($processTypeString, $patterns, &$lastClass) {
            if ($node instanceof Node\Stmt\ClassLike) {
                $lastClass = $node;
            }
            if (!in_array(get_class($node), [Node\Stmt\Property::class, Node\Stmt\ClassMethod::class, Node\Expr\Assign::class], true)) {
                return;
            }
            $comment = CommentHelper::getDocComment($node);
            if ($comment === null) {
                return;
            }
            foreach ($patterns as $pattern) {
                preg_match_all($pattern, $comment, $matches, PREG_SET_ORDER);
                foreach ($matches as $match) {
                    $processTypeString($match[1], $className);
                }
            }
        });
        if (count($objectTypes) === 0) {
            return $typeMap;
        }
        $fileString = file_get_contents($fileName);
        if ($lastClass !== null) {
            $classType = 'class';
            if ($lastClass instanceof Interface_) {
                $classType = 'interface';
            } elseif ($lastClass instanceof Trait_) {
                $classType = 'trait';
            }
            $classTypePosition = strpos($fileString, sprintf('%s %s', $classType, $lastClass->name));
            $nameResolveInfluencingPart = trim(substr($fileString, 0, $classTypePosition));
        } else {
            $nameResolveInfluencingPart = $fileString;
        }
        if (substr($nameResolveInfluencingPart, -strlen('final')) === 'final') {
            $nameResolveInfluencingPart = trim(substr($nameResolveInfluencingPart, 0, -strlen('final')));
        }
        if (substr($nameResolveInfluencingPart, -strlen('abstract')) === 'abstract') {
            $nameResolveInfluencingPart = trim(substr($nameResolveInfluencingPart, 0, -strlen('abstract')));
        }
        $namespace = null;
        $uses = [];
        $this->processNodes($this->parser->parseString($nameResolveInfluencingPart), function (\PhpParser\Node $node) use($processTypeString, $patterns, &$namespace, &$uses) {
            if ($node instanceof \PhpParser\Node\Stmt\Namespace_) {
                $namespace = (string) $node->name;
            } elseif ($node instanceof \PhpParser\Node\Stmt\Use_ && $node->type === \PhpParser\Node\Stmt\Use_::TYPE_NORMAL) {
                foreach ($node->uses as $use) {
                    $uses[$use->alias] = (string) $use->name;
                }
            } elseif ($node instanceof \PhpParser\Node\Stmt\GroupUse) {
                $prefix = (string) $node->prefix;
                foreach ($node->uses as $use) {
                    if ($node->type === \PhpParser\Node\Stmt\Use_::TYPE_NORMAL || $use->type === \PhpParser\Node\Stmt\Use_::TYPE_NORMAL) {
                        $uses[$use->alias] = sprintf('%s\\%s', $prefix, $use->name);
                    }
                }
            }
        });
        foreach ($objectTypes as $key => $objectType) {
            $objectTypeType = $objectType['type'];
            $objectTypeTypeClass = $objectTypeType->getClass();
            if (preg_match('#^[a-zA-Z_\\\\]#', $objectTypeTypeClass) === 0) {
                unset($objectTypes[$key]);
                continue;
            }
            if (strtolower($objectTypeTypeClass) === 'new') {
                unset($objectTypes[$key]);
                continue;
            }
        }
        foreach ($objectTypes as $objectType) {
            if (isset($objectType['arrayType'])) {
                $arrayType = $objectType['arrayType'];
                $typeMap[$objectType['typeString']] = ArrayType::createDeepArrayType(new NestedArrayItemType(new ObjectType($this->resolveStringName($namespace, $objectType['type']->getClass(), $uses), false), $arrayType['depth']), $arrayType['nullable']);
            } else {
                $objectTypeString = $objectType['typeString'];
                $objectTypeType = $objectType['type'];
                $typeMap[$objectTypeString] = new ObjectType($this->resolveStringName($namespace, $objectType['type']->getClass(), $uses), $objectTypeType->isNullable());
            }
        }
        return $typeMap;
    }