> */ private const NODE_NAME_RESOLVER_CLASSES = [ClassConstFetchNameResolver::class, ClassConstNameResolver::class, ClassNameResolver::class, FuncCallNameResolver::class, FunctionNameResolver::class, NameNameResolver::class, ParamNameResolver::class, PropertyNameResolver::class, UseNameResolver::class, VariableNameResolver::class]; /** * @var array> */ private const BASE_PHP_DOC_NODE_VISITORS = [ArrayTypePhpDocNodeVisitor::class, CallableTypePhpDocNodeVisitor::class, IntersectionTypeNodePhpDocNodeVisitor::class, TemplatePhpDocNodeVisitor::class, UnionTypeNodePhpDocNodeVisitor::class]; /** * @var array> */ private const ANNOTATION_TO_ATTRIBUTE_MAPPER_CLASSES = [ArrayAnnotationToAttributeMapper::class, ArrayItemNodeAnnotationToAttributeMapper::class, ClassConstFetchAnnotationToAttributeMapper::class, ConstExprNodeAnnotationToAttributeMapper::class, CurlyListNodeAnnotationToAttributeMapper::class, DoctrineAnnotationAnnotationToAttributeMapper::class, StringAnnotationToAttributeMapper::class, StringNodeAnnotationToAttributeMapper::class]; /** * @var array> */ private const SCOPE_RESOLVER_NODE_VISITOR_CLASSES = [ArgNodeVisitor::class, AssignedToNodeVisitor::class, ByRefReturnNodeVisitor::class, ByRefVariableNodeVisitor::class, ContextNodeVisitor::class, GlobalVariableNodeVisitor::class, NameNodeVisitor::class, StaticVariableNodeVisitor::class, StmtKeyNodeVisitor::class]; /** * @var array> */ private const PHPDOC_TYPE_MAPPER_CLASSES = [IdentifierPhpDocTypeMapper::class, IntersectionPhpDocTypeMapper::class, NullablePhpDocTypeMapper::class, UnionPhpDocTypeMapper::class]; /** * @var array> */ private const CLASS_NAME_IMPORT_SKIPPER_CLASSES = [AliasClassNameImportSkipVoter::class, ClassLikeNameClassNameImportSkipVoter::class, FullyQualifiedNameClassNameImportSkipVoter::class, UsesClassNameImportSkipVoter::class]; /** * @var array> */ private const TYPE_MAPPER_CLASSES = [AccessoryLiteralStringTypeMapper::class, AccessoryNonEmptyStringTypeMapper::class, AccessoryNonFalsyStringTypeMapper::class, AccessoryNumericStringTypeMapper::class, ArrayTypeMapper::class, BooleanTypeMapper::class, CallableTypeMapper::class, ClassStringTypeMapper::class, ClosureTypeMapper::class, ConditionalTypeForParameterMapper::class, ConditionalTypeMapper::class, FloatTypeMapper::class, GenericClassStringTypeMapper::class, HasMethodTypeMapper::class, HasOffsetTypeMapper::class, HasOffsetValueTypeTypeMapper::class, HasPropertyTypeMapper::class, IntegerTypeMapper::class, IntersectionTypeMapper::class, IterableTypeMapper::class, MixedTypeMapper::class, NeverTypeMapper::class, NonEmptyArrayTypeMapper::class, NullTypeMapper::class, ObjectTypeMapper::class, ObjectWithoutClassTypeMapper::class, OversizedArrayTypeMapper::class, ParentStaticTypeMapper::class, ResourceTypeMapper::class, SelfObjectTypeMapper::class, StaticTypeMapper::class, StrictMixedTypeMapper::class, StringTypeMapper::class, ThisTypeMapper::class, TypeWithClassNameTypeMapper::class, UnionTypeMapper::class, VoidTypeMapper::class]; /** * @var array> */ private const PHP_DOC_NODE_DECORATOR_CLASSES = [ConstExprClassNameDecorator::class, DoctrineAnnotationDecorator::class, ArrayItemClassNameDecorator::class]; /** * @var array */ private const PUBLIC_PHPSTAN_SERVICE_TYPES = [ScopeFactory::class, TypeNodeResolver::class, NodeScopeResolver::class, ReflectionProvider::class, CachingVisitor::class]; /** * @var array> */ private const OUTPUT_FORMATTER_CLASSES = [ConsoleOutputFormatter::class, JsonOutputFormatter::class]; /** * @var array> */ private const NODE_TYPE_RESOLVER_CLASSES = [CastTypeResolver::class, StaticCallMethodCallTypeResolver::class, ClassAndInterfaceTypeResolver::class, IdentifierTypeResolver::class, NameTypeResolver::class, NewTypeResolver::class, ParamTypeResolver::class, PropertyFetchTypeResolver::class, ClassConstFetchTypeResolver::class, PropertyTypeResolver::class, ScalarTypeResolver::class, TraitTypeResolver::class]; /** * @var array> */ private const PHP_PARSER_NODE_MAPPER_CLASSES = [FullyQualifiedNodeMapper::class, IdentifierNodeMapper::class, IntersectionTypeNodeMapper::class, NameNodeMapper::class, NullableTypeNodeMapper::class, StringNodeMapper::class, UnionTypeNodeMapper::class, ExprNodeMapper::class]; /** * @var array> */ private const CONVERTER_ATTRIBUTE_DECORATOR_CLASSES = [SensioParamConverterAttributeDecorator::class, DoctrineConverterAttributeDecorator::class]; /** * @api used as next rectorConfig factory */ public function create() : RectorConfig { $rectorConfig = new RectorConfig(); $rectorConfig->import(__DIR__ . '/../../config/config.php'); $rectorConfig->singleton(Application::class, static function (Container $container) : Application { $application = $container->make(ConsoleApplication::class); $commandNamesToHide = ['list', 'completion', 'help', 'worker']; foreach ($commandNamesToHide as $commandNameToHide) { $commandToHide = $application->get($commandNameToHide); $commandToHide->setHidden(); } return $application; }); $rectorConfig->when(ConsoleApplication::class)->needs('$commands')->giveTagged(Command::class); $rectorConfig->singleton(Inflector::class, static function () : Inflector { $inflectorFactory = new InflectorFactory(); return $inflectorFactory->build(); }); $rectorConfig->singleton(ProcessCommand::class); $rectorConfig->singleton(WorkerCommand::class); $rectorConfig->singleton(SetupCICommand::class); $rectorConfig->singleton(ListRulesCommand::class); $rectorConfig->singleton(CustomRuleCommand::class); $rectorConfig->when(ListRulesCommand::class)->needs('$rectors')->giveTagged(RectorInterface::class); $rectorConfig->singleton(FileProcessor::class); $rectorConfig->singleton(PostFileProcessor::class); // phpdoc-parser $rectorConfig->when(TypeParser::class)->needs('$usedAttributes')->give(['lines' => \true, 'indexes' => \true]); $rectorConfig->when(ConstExprParser::class)->needs('$usedAttributes')->give(['lines' => \true, 'indexes' => \true]); $rectorConfig->alias(TypeParser::class, BetterTypeParser::class); $rectorConfig->when(RectorNodeTraverser::class)->needs('$rectors')->giveTagged(RectorInterface::class); $rectorConfig->when(ConfigInitializer::class)->needs('$rectors')->giveTagged(RectorInterface::class); $rectorConfig->when(ClassNameImportSkipper::class)->needs('$classNameImportSkipVoters')->giveTagged(ClassNameImportSkipVoterInterface::class); $rectorConfig->singleton(DynamicSourceLocatorProvider::class, static function (Container $container) : DynamicSourceLocatorProvider { $phpStanServicesFactory = $container->make(PHPStanServicesFactory::class); return $phpStanServicesFactory->createDynamicSourceLocatorProvider(); }); // resetables $rectorConfig->tag(DynamicSourceLocatorProvider::class, ResetableInterface::class); $rectorConfig->tag(RenamedClassesDataCollector::class, ResetableInterface::class); // caching $rectorConfig->singleton(Cache::class, static function (Container $container) : Cache { /** @var CacheFactory $cacheFactory */ $cacheFactory = $container->make(CacheFactory::class); return $cacheFactory->create(); }); // tagged services $rectorConfig->when(BetterPhpDocParser::class)->needs('$phpDocNodeDecorators')->giveTagged(PhpDocNodeDecoratorInterface::class); $rectorConfig->afterResolving(ArrayTypeMapper::class, static function (ArrayTypeMapper $arrayTypeMapper, Container $container) : void { $arrayTypeMapper->autowire($container->make(PHPStanStaticTypeMapper::class)); }); $rectorConfig->afterResolving(ConditionalTypeForParameterMapper::class, static function (ConditionalTypeForParameterMapper $conditionalTypeForParameterMapper, Container $container) : void { $phpStanStaticTypeMapper = $container->make(PHPStanStaticTypeMapper::class); $conditionalTypeForParameterMapper->autowire($phpStanStaticTypeMapper); }); $rectorConfig->afterResolving(ConditionalTypeMapper::class, static function (ConditionalTypeMapper $conditionalTypeMapper, Container $container) : void { $phpStanStaticTypeMapper = $container->make(PHPStanStaticTypeMapper::class); $conditionalTypeMapper->autowire($phpStanStaticTypeMapper); }); $rectorConfig->afterResolving(UnionTypeMapper::class, static function (UnionTypeMapper $unionTypeMapper, Container $container) : void { $phpStanStaticTypeMapper = $container->make(PHPStanStaticTypeMapper::class); $unionTypeMapper->autowire($phpStanStaticTypeMapper); }); $rectorConfig->when(PHPStanStaticTypeMapper::class)->needs('$typeMappers')->giveTagged(TypeMapperInterface::class); $rectorConfig->when(PhpDocTypeMapper::class)->needs('$phpDocTypeMappers')->giveTagged(PhpDocTypeMapperInterface::class); $rectorConfig->when(PhpParserNodeMapper::class)->needs('$phpParserNodeMappers')->giveTagged(PhpParserNodeMapperInterface::class); $rectorConfig->when(NodeTypeResolver::class)->needs('$nodeTypeResolvers')->giveTagged(NodeTypeResolverInterface::class); // node name resolvers $rectorConfig->when(NodeNameResolver::class)->needs('$nodeNameResolvers')->giveTagged(NodeNameResolverInterface::class); $rectorConfig->when(AttributeGroupNamedArgumentManipulator::class)->needs('$converterAttributeDecorators')->giveTagged(ConverterAttributeDecoratorInterface::class); $this->registerTagged($rectorConfig, self::CONVERTER_ATTRIBUTE_DECORATOR_CLASSES, ConverterAttributeDecoratorInterface::class); $rectorConfig->afterResolving(AbstractRector::class, static function (AbstractRector $rector, Container $container) : void { $rector->autowire($container->get(NodeNameResolver::class), $container->get(NodeTypeResolver::class), $container->get(SimpleCallableNodeTraverser::class), $container->get(NodeFactory::class), $container->get(Skipper::class), $container->get(NodeComparator::class), $container->get(CurrentFileProvider::class), $container->get(CreatedByRuleDecorator::class), $container->get(ChangedNodeScopeRefresher::class)); }); $this->registerTagged($rectorConfig, self::PHP_PARSER_NODE_MAPPER_CLASSES, PhpParserNodeMapperInterface::class); $this->registerTagged($rectorConfig, self::PHP_DOC_NODE_DECORATOR_CLASSES, PhpDocNodeDecoratorInterface::class); $this->registerTagged($rectorConfig, self::BASE_PHP_DOC_NODE_VISITORS, BasePhpDocNodeVisitorInterface::class); // PHP 8.0 attributes $this->registerTagged($rectorConfig, self::ANNOTATION_TO_ATTRIBUTE_MAPPER_CLASSES, AnnotationToAttributeMapperInterface::class); $this->registerTagged($rectorConfig, self::TYPE_MAPPER_CLASSES, TypeMapperInterface::class); $this->registerTagged($rectorConfig, self::PHPDOC_TYPE_MAPPER_CLASSES, PhpDocTypeMapperInterface::class); $this->registerTagged($rectorConfig, self::NODE_NAME_RESOLVER_CLASSES, NodeNameResolverInterface::class); $this->registerTagged($rectorConfig, self::NODE_TYPE_RESOLVER_CLASSES, NodeTypeResolverInterface::class); $this->registerTagged($rectorConfig, self::OUTPUT_FORMATTER_CLASSES, OutputFormatterInterface::class); $this->registerTagged($rectorConfig, self::BASE_PHP_DOC_NODE_VISITORS, BasePhpDocNodeVisitorInterface::class); $this->registerTagged($rectorConfig, self::CLASS_NAME_IMPORT_SKIPPER_CLASSES, ClassNameImportSkipVoterInterface::class); $rectorConfig->alias(SymfonyStyle::class, RectorStyle::class); $rectorConfig->singleton(SymfonyStyle::class, static function (Container $container) : SymfonyStyle { $symfonyStyleFactory = $container->make(SymfonyStyleFactory::class); return $symfonyStyleFactory->create(); }); $rectorConfig->when(AnnotationToAttributeMapper::class)->needs('$annotationToAttributeMappers')->giveTagged(AnnotationToAttributeMapperInterface::class); $rectorConfig->when(OutputFormatterCollector::class)->needs('$outputFormatters')->giveTagged(OutputFormatterInterface::class); // required-like setter $rectorConfig->afterResolving(ArrayAnnotationToAttributeMapper::class, static function (ArrayAnnotationToAttributeMapper $arrayAnnotationToAttributeMapper, Container $container) : void { $annotationToAttributesMapper = $container->make(AnnotationToAttributeMapper::class); $arrayAnnotationToAttributeMapper->autowire($annotationToAttributesMapper); }); $rectorConfig->afterResolving(ArrayItemNodeAnnotationToAttributeMapper::class, static function (ArrayItemNodeAnnotationToAttributeMapper $arrayItemNodeAnnotationToAttributeMapper, Container $container) : void { $annotationToAttributeMapper = $container->make(AnnotationToAttributeMapper::class); $arrayItemNodeAnnotationToAttributeMapper->autowire($annotationToAttributeMapper); }); $rectorConfig->afterResolving(PlainValueParser::class, static function (PlainValueParser $plainValueParser, Container $container) : void { $plainValueParser->autowire($container->make(StaticDoctrineAnnotationParser::class), $container->make(ArrayParser::class)); }); $rectorConfig->afterResolving(CurlyListNodeAnnotationToAttributeMapper::class, static function (CurlyListNodeAnnotationToAttributeMapper $curlyListNodeAnnotationToAttributeMapper, Container $container) : void { $annotationToAttributeMapper = $container->make(AnnotationToAttributeMapper::class); $curlyListNodeAnnotationToAttributeMapper->autowire($annotationToAttributeMapper); }); $rectorConfig->afterResolving(DoctrineAnnotationAnnotationToAttributeMapper::class, static function (DoctrineAnnotationAnnotationToAttributeMapper $doctrineAnnotationAnnotationToAttributeMapper, Container $container) : void { $annotationToAttributeMapper = $container->make(AnnotationToAttributeMapper::class); $doctrineAnnotationAnnotationToAttributeMapper->autowire($annotationToAttributeMapper); }); $rectorConfig->when(PHPStanNodeScopeResolver::class)->needs('$nodeVisitors')->giveTagged(ScopeResolverNodeVisitorInterface::class); $this->registerTagged($rectorConfig, self::SCOPE_RESOLVER_NODE_VISITOR_CLASSES, ScopeResolverNodeVisitorInterface::class); $this->createPHPStanServices($rectorConfig); $rectorConfig->when(PhpDocNodeMapper::class)->needs('$phpDocNodeVisitors')->giveTagged(BasePhpDocNodeVisitorInterface::class); return $rectorConfig; } /** * @param array $classes * @param class-string $tagInterface */ private function registerTagged(Container $container, array $classes, string $tagInterface) : void { foreach ($classes as $class) { Assert::isAOf($class, $tagInterface); $container->singleton($class); $container->tag($class, $tagInterface); } } private function createPHPStanServices(RectorConfig $rectorConfig) : void { $rectorConfig->singleton(Parser::class, static function (Container $container) { $phpstanServiceFactory = $container->make(PHPStanServicesFactory::class); return $phpstanServiceFactory->createPHPStanParser(); }); $rectorConfig->singleton(Lexer::class, static function (Container $container) { $phpstanServiceFactory = $container->make(PHPStanServicesFactory::class); return $phpstanServiceFactory->createEmulativeLexer(); }); foreach (self::PUBLIC_PHPSTAN_SERVICE_TYPES as $publicPhpstanServiceType) { $rectorConfig->singleton($publicPhpstanServiceType, static function (Container $container) use($publicPhpstanServiceType) { $phpstanServiceFactory = $container->make(PHPStanServicesFactory::class); return $phpstanServiceFactory->getByType($publicPhpstanServiceType); }); } } }