Repository: symfony/symfony
File: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/PhpConfigReferenceDumpPass.php (PHP)

Code before:
        PHPDOC;

    public function __construct(
        private string $referenceFile,
        private array $bundlesDefinition,
    ) {
    }

    public function process(ContainerBuilder $container): void
    {
        $knownEnvs = $container->hasParameter('.container.known_envs') ? $container->getParameter('.container.known_envs') : [$container->getParameter('kernel.environment')];
        $knownEnvs = array_unique($knownEnvs);
        sort($knownEnvs);
        $extensionsPerEnv = [];
        $appTypes = '';

        $anyEnvExtensions = [];
        foreach ($this->bundlesDefinition as $bundle => $envs) {
            if (!is_subclass_of($bundle, BundleInterface::class)) {
                continue;
            }
            if (!$extension = (new $bundle())->getContainerExtension()) {
                continue;
            }
            if ($container->hasExtension($extension->getAlias())) {
                $extension = $container->getExtension($extension->getAlias());
            }
            if (!$configuration = $this->getConfiguration($extension, $container)) {
                continue;
            }
            $anyEnvExtensions[$bundle] = $extension;
            $type = $this->camelCase($extension->getAlias()).'Config';
            $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree()));

            foreach ($knownEnvs as $env) {
                if ($envs[$env] ?? $envs['all'] ?? false) {
                    $extensionsPerEnv[$env][] = $extension;
                } else {
                    unset($anyEnvExtensions[$bundle]);
                }
            }
        }
        krsort($extensionsPerEnv);

        $r = new \ReflectionClass(AppReference::class);

        if (false === $i = strpos($phpdoc = $r->getDocComment(), "\n * @psalm-type ConfigType = ")) {
            throw new \LogicException(\sprintf('Cannot insert config shape in "%s".', AppReference::class));
        }
        $appTypes = substr_replace($phpdoc, $appTypes, $i, 0);


Review comment (suggestion):
[just a note] this highlights that extensions can exist outside bundles, in practice, someone could register an extension in the kernel via `$container->registerExtension()` for custom app config, so we might be missing those configs currently.

it could deserve another iteration outside this foreach block, for `$container->getExtensions()` (excluding extensions already processed).

Code after:
        PHPDOC;

    public function __construct(
        private string $referenceFile,
        private array $bundlesDefinition,
    ) {
    }

    public function process(ContainerBuilder $container): void
    {
        $knownEnvs = $container->hasParameter('.container.known_envs') ? $container->getParameter('.container.known_envs') : [$container->getParameter('kernel.environment')];
        $knownEnvs = array_unique($knownEnvs);
        sort($knownEnvs);
        $extensionsPerEnv = [];
        $appTypes = '';

        $anyEnvExtensions = [];
        foreach ($container->getExtensions() as $alias => $extension) {
            if (!$configuration = $this->getConfiguration($extension, $container)) {
                continue;
            }

            $anyEnvExtensions[$alias] = $extension;
            $type = $this->camelCase($alias).'Config';
            $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree()));
        }
        foreach ($this->bundlesDefinition as $bundle => $envs) {
            if (!is_subclass_of($bundle, BundleInterface::class)) {
                continue;
            }
            if (!$extension = (new $bundle())->getContainerExtension()) {
                continue;
            }
            if (!$configuration = $this->getConfiguration($extension, $container)) {
                continue;
            }

            $extensionAlias = $extension->getAlias();
            if (isset($anyEnvExtensions[$extensionAlias])) {
                $extension = $anyEnvExtensions[$extensionAlias];
            } else {
                $anyEnvExtensions[$extensionAlias] = $extension;
                $type = $this->camelCase($extensionAlias).'Config';
                $appTypes .= \sprintf("\n * @psalm-type %s = %s", $type, ArrayShapeGenerator::generate($configuration->getConfigTreeBuilder()->buildTree()));
            }

            foreach ($knownEnvs as $env) {
                if ($envs[$env] ?? $envs['all'] ?? false) {
                    $extensionsPerEnv[$env][] = $extension;
                } else {
                    unset($anyEnvExtensions[$extensionAlias]);